18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * HighPoint RR3xxx/4xxx controller driver for Linux
48c2ecf20Sopenharmony_ci * Copyright (C) 2006-2015 HighPoint Technologies, Inc. All Rights Reserved.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Please report bugs/comments/suggestions to linux@highpoint-tech.com
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * For more information, visit http://www.highpoint-tech.com
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/types.h>
128c2ecf20Sopenharmony_ci#include <linux/string.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/pci.h>
158c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
168c2ecf20Sopenharmony_ci#include <linux/errno.h>
178c2ecf20Sopenharmony_ci#include <linux/delay.h>
188c2ecf20Sopenharmony_ci#include <linux/timer.h>
198c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
208c2ecf20Sopenharmony_ci#include <linux/gfp.h>
218c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
228c2ecf20Sopenharmony_ci#include <asm/io.h>
238c2ecf20Sopenharmony_ci#include <asm/div64.h>
248c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h>
258c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
268c2ecf20Sopenharmony_ci#include <scsi/scsi.h>
278c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h>
288c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include "hptiop.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ciMODULE_AUTHOR("HighPoint Technologies, Inc.");
338c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("HighPoint RocketRAID 3xxx/4xxx Controller Driver");
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic char driver_name[] = "hptiop";
368c2ecf20Sopenharmony_cistatic const char driver_name_long[] = "RocketRAID 3xxx/4xxx Controller driver";
378c2ecf20Sopenharmony_cistatic const char driver_ver[] = "v1.10.0";
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec);
408c2ecf20Sopenharmony_cistatic void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
418c2ecf20Sopenharmony_ci				struct hpt_iop_request_scsi_command *req);
428c2ecf20Sopenharmony_cistatic void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 tag);
438c2ecf20Sopenharmony_cistatic void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag);
448c2ecf20Sopenharmony_cistatic void hptiop_message_callback(struct hptiop_hba *hba, u32 msg);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic int iop_wait_ready_itl(struct hptiop_hba *hba, u32 millisec)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	u32 req = 0;
498c2ecf20Sopenharmony_ci	int i;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	for (i = 0; i < millisec; i++) {
528c2ecf20Sopenharmony_ci		req = readl(&hba->u.itl.iop->inbound_queue);
538c2ecf20Sopenharmony_ci		if (req != IOPMU_QUEUE_EMPTY)
548c2ecf20Sopenharmony_ci			break;
558c2ecf20Sopenharmony_ci		msleep(1);
568c2ecf20Sopenharmony_ci	}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if (req != IOPMU_QUEUE_EMPTY) {
598c2ecf20Sopenharmony_ci		writel(req, &hba->u.itl.iop->outbound_queue);
608c2ecf20Sopenharmony_ci		readl(&hba->u.itl.iop->outbound_intstatus);
618c2ecf20Sopenharmony_ci		return 0;
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	return -1;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int iop_wait_ready_mv(struct hptiop_hba *hba, u32 millisec)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	return iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_NOP, millisec);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic int iop_wait_ready_mvfrey(struct hptiop_hba *hba, u32 millisec)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	return iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_NOP, millisec);
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic void hptiop_request_callback_itl(struct hptiop_hba *hba, u32 tag)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	if (tag & IOPMU_QUEUE_ADDR_HOST_BIT)
808c2ecf20Sopenharmony_ci		hptiop_host_request_callback_itl(hba,
818c2ecf20Sopenharmony_ci				tag & ~IOPMU_QUEUE_ADDR_HOST_BIT);
828c2ecf20Sopenharmony_ci	else
838c2ecf20Sopenharmony_ci		hptiop_iop_request_callback_itl(hba, tag);
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic void hptiop_drain_outbound_queue_itl(struct hptiop_hba *hba)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	u32 req;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	while ((req = readl(&hba->u.itl.iop->outbound_queue)) !=
918c2ecf20Sopenharmony_ci						IOPMU_QUEUE_EMPTY) {
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci		if (req & IOPMU_QUEUE_MASK_HOST_BITS)
948c2ecf20Sopenharmony_ci			hptiop_request_callback_itl(hba, req);
958c2ecf20Sopenharmony_ci		else {
968c2ecf20Sopenharmony_ci			struct hpt_iop_request_header __iomem * p;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci			p = (struct hpt_iop_request_header __iomem *)
998c2ecf20Sopenharmony_ci				((char __iomem *)hba->u.itl.iop + req);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci			if (readl(&p->flags) & IOP_REQUEST_FLAG_SYNC_REQUEST) {
1028c2ecf20Sopenharmony_ci				if (readl(&p->context))
1038c2ecf20Sopenharmony_ci					hptiop_request_callback_itl(hba, req);
1048c2ecf20Sopenharmony_ci				else
1058c2ecf20Sopenharmony_ci					writel(1, &p->context);
1068c2ecf20Sopenharmony_ci			}
1078c2ecf20Sopenharmony_ci			else
1088c2ecf20Sopenharmony_ci				hptiop_request_callback_itl(hba, req);
1098c2ecf20Sopenharmony_ci		}
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic int iop_intr_itl(struct hptiop_hba *hba)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	struct hpt_iopmu_itl __iomem *iop = hba->u.itl.iop;
1168c2ecf20Sopenharmony_ci	void __iomem *plx = hba->u.itl.plx;
1178c2ecf20Sopenharmony_ci	u32 status;
1188c2ecf20Sopenharmony_ci	int ret = 0;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (plx && readl(plx + 0x11C5C) & 0xf)
1218c2ecf20Sopenharmony_ci		writel(1, plx + 0x11C60);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	status = readl(&iop->outbound_intstatus);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	if (status & IOPMU_OUTBOUND_INT_MSG0) {
1268c2ecf20Sopenharmony_ci		u32 msg = readl(&iop->outbound_msgaddr0);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci		dprintk("received outbound msg %x\n", msg);
1298c2ecf20Sopenharmony_ci		writel(IOPMU_OUTBOUND_INT_MSG0, &iop->outbound_intstatus);
1308c2ecf20Sopenharmony_ci		hptiop_message_callback(hba, msg);
1318c2ecf20Sopenharmony_ci		ret = 1;
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	if (status & IOPMU_OUTBOUND_INT_POSTQUEUE) {
1358c2ecf20Sopenharmony_ci		hptiop_drain_outbound_queue_itl(hba);
1368c2ecf20Sopenharmony_ci		ret = 1;
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	return ret;
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic u64 mv_outbound_read(struct hpt_iopmu_mv __iomem *mu)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	u32 outbound_tail = readl(&mu->outbound_tail);
1458c2ecf20Sopenharmony_ci	u32 outbound_head = readl(&mu->outbound_head);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (outbound_tail != outbound_head) {
1488c2ecf20Sopenharmony_ci		u64 p;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci		memcpy_fromio(&p, &mu->outbound_q[mu->outbound_tail], 8);
1518c2ecf20Sopenharmony_ci		outbound_tail++;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci		if (outbound_tail == MVIOP_QUEUE_LEN)
1548c2ecf20Sopenharmony_ci			outbound_tail = 0;
1558c2ecf20Sopenharmony_ci		writel(outbound_tail, &mu->outbound_tail);
1568c2ecf20Sopenharmony_ci		return p;
1578c2ecf20Sopenharmony_ci	} else
1588c2ecf20Sopenharmony_ci		return 0;
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic void mv_inbound_write(u64 p, struct hptiop_hba *hba)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	u32 inbound_head = readl(&hba->u.mv.mu->inbound_head);
1648c2ecf20Sopenharmony_ci	u32 head = inbound_head + 1;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	if (head == MVIOP_QUEUE_LEN)
1678c2ecf20Sopenharmony_ci		head = 0;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	memcpy_toio(&hba->u.mv.mu->inbound_q[inbound_head], &p, 8);
1708c2ecf20Sopenharmony_ci	writel(head, &hba->u.mv.mu->inbound_head);
1718c2ecf20Sopenharmony_ci	writel(MVIOP_MU_INBOUND_INT_POSTQUEUE,
1728c2ecf20Sopenharmony_ci			&hba->u.mv.regs->inbound_doorbell);
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic void hptiop_request_callback_mv(struct hptiop_hba *hba, u64 tag)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	u32 req_type = (tag >> 5) & 0x7;
1788c2ecf20Sopenharmony_ci	struct hpt_iop_request_scsi_command *req;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	dprintk("hptiop_request_callback_mv: tag=%llx\n", tag);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	BUG_ON((tag & MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT) == 0);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	switch (req_type) {
1858c2ecf20Sopenharmony_ci	case IOP_REQUEST_TYPE_GET_CONFIG:
1868c2ecf20Sopenharmony_ci	case IOP_REQUEST_TYPE_SET_CONFIG:
1878c2ecf20Sopenharmony_ci		hba->msg_done = 1;
1888c2ecf20Sopenharmony_ci		break;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	case IOP_REQUEST_TYPE_SCSI_COMMAND:
1918c2ecf20Sopenharmony_ci		req = hba->reqs[tag >> 8].req_virt;
1928c2ecf20Sopenharmony_ci		if (likely(tag & MVIOP_MU_QUEUE_REQUEST_RESULT_BIT))
1938c2ecf20Sopenharmony_ci			req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci		hptiop_finish_scsi_req(hba, tag>>8, req);
1968c2ecf20Sopenharmony_ci		break;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	default:
1998c2ecf20Sopenharmony_ci		break;
2008c2ecf20Sopenharmony_ci	}
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_cistatic int iop_intr_mv(struct hptiop_hba *hba)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	u32 status;
2068c2ecf20Sopenharmony_ci	int ret = 0;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	status = readl(&hba->u.mv.regs->outbound_doorbell);
2098c2ecf20Sopenharmony_ci	writel(~status, &hba->u.mv.regs->outbound_doorbell);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if (status & MVIOP_MU_OUTBOUND_INT_MSG) {
2128c2ecf20Sopenharmony_ci		u32 msg;
2138c2ecf20Sopenharmony_ci		msg = readl(&hba->u.mv.mu->outbound_msg);
2148c2ecf20Sopenharmony_ci		dprintk("received outbound msg %x\n", msg);
2158c2ecf20Sopenharmony_ci		hptiop_message_callback(hba, msg);
2168c2ecf20Sopenharmony_ci		ret = 1;
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	if (status & MVIOP_MU_OUTBOUND_INT_POSTQUEUE) {
2208c2ecf20Sopenharmony_ci		u64 tag;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci		while ((tag = mv_outbound_read(hba->u.mv.mu)))
2238c2ecf20Sopenharmony_ci			hptiop_request_callback_mv(hba, tag);
2248c2ecf20Sopenharmony_ci		ret = 1;
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	return ret;
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic void hptiop_request_callback_mvfrey(struct hptiop_hba *hba, u32 _tag)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	u32 req_type = _tag & 0xf;
2338c2ecf20Sopenharmony_ci	struct hpt_iop_request_scsi_command *req;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	switch (req_type) {
2368c2ecf20Sopenharmony_ci	case IOP_REQUEST_TYPE_GET_CONFIG:
2378c2ecf20Sopenharmony_ci	case IOP_REQUEST_TYPE_SET_CONFIG:
2388c2ecf20Sopenharmony_ci		hba->msg_done = 1;
2398c2ecf20Sopenharmony_ci		break;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	case IOP_REQUEST_TYPE_SCSI_COMMAND:
2428c2ecf20Sopenharmony_ci		req = hba->reqs[(_tag >> 4) & 0xff].req_virt;
2438c2ecf20Sopenharmony_ci		if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT))
2448c2ecf20Sopenharmony_ci			req->header.result = IOP_RESULT_SUCCESS;
2458c2ecf20Sopenharmony_ci		hptiop_finish_scsi_req(hba, (_tag >> 4) & 0xff, req);
2468c2ecf20Sopenharmony_ci		break;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	default:
2498c2ecf20Sopenharmony_ci		break;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic int iop_intr_mvfrey(struct hptiop_hba *hba)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	u32 _tag, status, cptr, cur_rptr;
2568c2ecf20Sopenharmony_ci	int ret = 0;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	if (hba->initialized)
2598c2ecf20Sopenharmony_ci		writel(0, &(hba->u.mvfrey.mu->pcie_f0_int_enable));
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	status = readl(&(hba->u.mvfrey.mu->f0_doorbell));
2628c2ecf20Sopenharmony_ci	if (status) {
2638c2ecf20Sopenharmony_ci		writel(status, &(hba->u.mvfrey.mu->f0_doorbell));
2648c2ecf20Sopenharmony_ci		if (status & CPU_TO_F0_DRBL_MSG_BIT) {
2658c2ecf20Sopenharmony_ci			u32 msg = readl(&(hba->u.mvfrey.mu->cpu_to_f0_msg_a));
2668c2ecf20Sopenharmony_ci			dprintk("received outbound msg %x\n", msg);
2678c2ecf20Sopenharmony_ci			hptiop_message_callback(hba, msg);
2688c2ecf20Sopenharmony_ci		}
2698c2ecf20Sopenharmony_ci		ret = 1;
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	status = readl(&(hba->u.mvfrey.mu->isr_cause));
2738c2ecf20Sopenharmony_ci	if (status) {
2748c2ecf20Sopenharmony_ci		writel(status, &(hba->u.mvfrey.mu->isr_cause));
2758c2ecf20Sopenharmony_ci		do {
2768c2ecf20Sopenharmony_ci			cptr = *hba->u.mvfrey.outlist_cptr & 0xff;
2778c2ecf20Sopenharmony_ci			cur_rptr = hba->u.mvfrey.outlist_rptr;
2788c2ecf20Sopenharmony_ci			while (cur_rptr != cptr) {
2798c2ecf20Sopenharmony_ci				cur_rptr++;
2808c2ecf20Sopenharmony_ci				if (cur_rptr ==	hba->u.mvfrey.list_count)
2818c2ecf20Sopenharmony_ci					cur_rptr = 0;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci				_tag = hba->u.mvfrey.outlist[cur_rptr].val;
2848c2ecf20Sopenharmony_ci				BUG_ON(!(_tag & IOPMU_QUEUE_MASK_HOST_BITS));
2858c2ecf20Sopenharmony_ci				hptiop_request_callback_mvfrey(hba, _tag);
2868c2ecf20Sopenharmony_ci				ret = 1;
2878c2ecf20Sopenharmony_ci			}
2888c2ecf20Sopenharmony_ci			hba->u.mvfrey.outlist_rptr = cur_rptr;
2898c2ecf20Sopenharmony_ci		} while (cptr != (*hba->u.mvfrey.outlist_cptr & 0xff));
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	if (hba->initialized)
2938c2ecf20Sopenharmony_ci		writel(0x1010, &(hba->u.mvfrey.mu->pcie_f0_int_enable));
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	return ret;
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic int iop_send_sync_request_itl(struct hptiop_hba *hba,
2998c2ecf20Sopenharmony_ci					void __iomem *_req, u32 millisec)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	struct hpt_iop_request_header __iomem *req = _req;
3028c2ecf20Sopenharmony_ci	u32 i;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	writel(readl(&req->flags) | IOP_REQUEST_FLAG_SYNC_REQUEST, &req->flags);
3058c2ecf20Sopenharmony_ci	writel(0, &req->context);
3068c2ecf20Sopenharmony_ci	writel((unsigned long)req - (unsigned long)hba->u.itl.iop,
3078c2ecf20Sopenharmony_ci			&hba->u.itl.iop->inbound_queue);
3088c2ecf20Sopenharmony_ci	readl(&hba->u.itl.iop->outbound_intstatus);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	for (i = 0; i < millisec; i++) {
3118c2ecf20Sopenharmony_ci		iop_intr_itl(hba);
3128c2ecf20Sopenharmony_ci		if (readl(&req->context))
3138c2ecf20Sopenharmony_ci			return 0;
3148c2ecf20Sopenharmony_ci		msleep(1);
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	return -1;
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic int iop_send_sync_request_mv(struct hptiop_hba *hba,
3218c2ecf20Sopenharmony_ci					u32 size_bits, u32 millisec)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	struct hpt_iop_request_header *reqhdr = hba->u.mv.internal_req;
3248c2ecf20Sopenharmony_ci	u32 i;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	hba->msg_done = 0;
3278c2ecf20Sopenharmony_ci	reqhdr->flags |= cpu_to_le32(IOP_REQUEST_FLAG_SYNC_REQUEST);
3288c2ecf20Sopenharmony_ci	mv_inbound_write(hba->u.mv.internal_req_phy |
3298c2ecf20Sopenharmony_ci			MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bits, hba);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	for (i = 0; i < millisec; i++) {
3328c2ecf20Sopenharmony_ci		iop_intr_mv(hba);
3338c2ecf20Sopenharmony_ci		if (hba->msg_done)
3348c2ecf20Sopenharmony_ci			return 0;
3358c2ecf20Sopenharmony_ci		msleep(1);
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci	return -1;
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic int iop_send_sync_request_mvfrey(struct hptiop_hba *hba,
3418c2ecf20Sopenharmony_ci					u32 size_bits, u32 millisec)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	struct hpt_iop_request_header *reqhdr =
3448c2ecf20Sopenharmony_ci		hba->u.mvfrey.internal_req.req_virt;
3458c2ecf20Sopenharmony_ci	u32 i;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	hba->msg_done = 0;
3488c2ecf20Sopenharmony_ci	reqhdr->flags |= cpu_to_le32(IOP_REQUEST_FLAG_SYNC_REQUEST);
3498c2ecf20Sopenharmony_ci	hba->ops->post_req(hba, &(hba->u.mvfrey.internal_req));
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	for (i = 0; i < millisec; i++) {
3528c2ecf20Sopenharmony_ci		iop_intr_mvfrey(hba);
3538c2ecf20Sopenharmony_ci		if (hba->msg_done)
3548c2ecf20Sopenharmony_ci			break;
3558c2ecf20Sopenharmony_ci		msleep(1);
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci	return hba->msg_done ? 0 : -1;
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_cistatic void hptiop_post_msg_itl(struct hptiop_hba *hba, u32 msg)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	writel(msg, &hba->u.itl.iop->inbound_msgaddr0);
3638c2ecf20Sopenharmony_ci	readl(&hba->u.itl.iop->outbound_intstatus);
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic void hptiop_post_msg_mv(struct hptiop_hba *hba, u32 msg)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	writel(msg, &hba->u.mv.mu->inbound_msg);
3698c2ecf20Sopenharmony_ci	writel(MVIOP_MU_INBOUND_INT_MSG, &hba->u.mv.regs->inbound_doorbell);
3708c2ecf20Sopenharmony_ci	readl(&hba->u.mv.regs->inbound_doorbell);
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic void hptiop_post_msg_mvfrey(struct hptiop_hba *hba, u32 msg)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	writel(msg, &(hba->u.mvfrey.mu->f0_to_cpu_msg_a));
3768c2ecf20Sopenharmony_ci	readl(&(hba->u.mvfrey.mu->f0_to_cpu_msg_a));
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	u32 i;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	hba->msg_done = 0;
3848c2ecf20Sopenharmony_ci	hba->ops->disable_intr(hba);
3858c2ecf20Sopenharmony_ci	hba->ops->post_msg(hba, msg);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	for (i = 0; i < millisec; i++) {
3888c2ecf20Sopenharmony_ci		spin_lock_irq(hba->host->host_lock);
3898c2ecf20Sopenharmony_ci		hba->ops->iop_intr(hba);
3908c2ecf20Sopenharmony_ci		spin_unlock_irq(hba->host->host_lock);
3918c2ecf20Sopenharmony_ci		if (hba->msg_done)
3928c2ecf20Sopenharmony_ci			break;
3938c2ecf20Sopenharmony_ci		msleep(1);
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	hba->ops->enable_intr(hba);
3978c2ecf20Sopenharmony_ci	return hba->msg_done? 0 : -1;
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic int iop_get_config_itl(struct hptiop_hba *hba,
4018c2ecf20Sopenharmony_ci				struct hpt_iop_request_get_config *config)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	u32 req32;
4048c2ecf20Sopenharmony_ci	struct hpt_iop_request_get_config __iomem *req;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	req32 = readl(&hba->u.itl.iop->inbound_queue);
4078c2ecf20Sopenharmony_ci	if (req32 == IOPMU_QUEUE_EMPTY)
4088c2ecf20Sopenharmony_ci		return -1;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	req = (struct hpt_iop_request_get_config __iomem *)
4118c2ecf20Sopenharmony_ci			((unsigned long)hba->u.itl.iop + req32);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	writel(0, &req->header.flags);
4148c2ecf20Sopenharmony_ci	writel(IOP_REQUEST_TYPE_GET_CONFIG, &req->header.type);
4158c2ecf20Sopenharmony_ci	writel(sizeof(struct hpt_iop_request_get_config), &req->header.size);
4168c2ecf20Sopenharmony_ci	writel(IOP_RESULT_PENDING, &req->header.result);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	if (iop_send_sync_request_itl(hba, req, 20000)) {
4198c2ecf20Sopenharmony_ci		dprintk("Get config send cmd failed\n");
4208c2ecf20Sopenharmony_ci		return -1;
4218c2ecf20Sopenharmony_ci	}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	memcpy_fromio(config, req, sizeof(*config));
4248c2ecf20Sopenharmony_ci	writel(req32, &hba->u.itl.iop->outbound_queue);
4258c2ecf20Sopenharmony_ci	return 0;
4268c2ecf20Sopenharmony_ci}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_cistatic int iop_get_config_mv(struct hptiop_hba *hba,
4298c2ecf20Sopenharmony_ci				struct hpt_iop_request_get_config *config)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	struct hpt_iop_request_get_config *req = hba->u.mv.internal_req;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
4348c2ecf20Sopenharmony_ci	req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_GET_CONFIG);
4358c2ecf20Sopenharmony_ci	req->header.size =
4368c2ecf20Sopenharmony_ci		cpu_to_le32(sizeof(struct hpt_iop_request_get_config));
4378c2ecf20Sopenharmony_ci	req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
4388c2ecf20Sopenharmony_ci	req->header.context = cpu_to_le32(IOP_REQUEST_TYPE_GET_CONFIG<<5);
4398c2ecf20Sopenharmony_ci	req->header.context_hi32 = 0;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	if (iop_send_sync_request_mv(hba, 0, 20000)) {
4428c2ecf20Sopenharmony_ci		dprintk("Get config send cmd failed\n");
4438c2ecf20Sopenharmony_ci		return -1;
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	memcpy(config, req, sizeof(struct hpt_iop_request_get_config));
4478c2ecf20Sopenharmony_ci	return 0;
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic int iop_get_config_mvfrey(struct hptiop_hba *hba,
4518c2ecf20Sopenharmony_ci				struct hpt_iop_request_get_config *config)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	struct hpt_iop_request_get_config *info = hba->u.mvfrey.config;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	if (info->header.size != sizeof(struct hpt_iop_request_get_config) ||
4568c2ecf20Sopenharmony_ci			info->header.type != IOP_REQUEST_TYPE_GET_CONFIG)
4578c2ecf20Sopenharmony_ci		return -1;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	config->interface_version = info->interface_version;
4608c2ecf20Sopenharmony_ci	config->firmware_version = info->firmware_version;
4618c2ecf20Sopenharmony_ci	config->max_requests = info->max_requests;
4628c2ecf20Sopenharmony_ci	config->request_size = info->request_size;
4638c2ecf20Sopenharmony_ci	config->max_sg_count = info->max_sg_count;
4648c2ecf20Sopenharmony_ci	config->data_transfer_length = info->data_transfer_length;
4658c2ecf20Sopenharmony_ci	config->alignment_mask = info->alignment_mask;
4668c2ecf20Sopenharmony_ci	config->max_devices = info->max_devices;
4678c2ecf20Sopenharmony_ci	config->sdram_size = info->sdram_size;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	return 0;
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_cistatic int iop_set_config_itl(struct hptiop_hba *hba,
4738c2ecf20Sopenharmony_ci				struct hpt_iop_request_set_config *config)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	u32 req32;
4768c2ecf20Sopenharmony_ci	struct hpt_iop_request_set_config __iomem *req;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	req32 = readl(&hba->u.itl.iop->inbound_queue);
4798c2ecf20Sopenharmony_ci	if (req32 == IOPMU_QUEUE_EMPTY)
4808c2ecf20Sopenharmony_ci		return -1;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	req = (struct hpt_iop_request_set_config __iomem *)
4838c2ecf20Sopenharmony_ci			((unsigned long)hba->u.itl.iop + req32);
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	memcpy_toio((u8 __iomem *)req + sizeof(struct hpt_iop_request_header),
4868c2ecf20Sopenharmony_ci		(u8 *)config + sizeof(struct hpt_iop_request_header),
4878c2ecf20Sopenharmony_ci		sizeof(struct hpt_iop_request_set_config) -
4888c2ecf20Sopenharmony_ci			sizeof(struct hpt_iop_request_header));
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	writel(0, &req->header.flags);
4918c2ecf20Sopenharmony_ci	writel(IOP_REQUEST_TYPE_SET_CONFIG, &req->header.type);
4928c2ecf20Sopenharmony_ci	writel(sizeof(struct hpt_iop_request_set_config), &req->header.size);
4938c2ecf20Sopenharmony_ci	writel(IOP_RESULT_PENDING, &req->header.result);
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	if (iop_send_sync_request_itl(hba, req, 20000)) {
4968c2ecf20Sopenharmony_ci		dprintk("Set config send cmd failed\n");
4978c2ecf20Sopenharmony_ci		return -1;
4988c2ecf20Sopenharmony_ci	}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	writel(req32, &hba->u.itl.iop->outbound_queue);
5018c2ecf20Sopenharmony_ci	return 0;
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic int iop_set_config_mv(struct hptiop_hba *hba,
5058c2ecf20Sopenharmony_ci				struct hpt_iop_request_set_config *config)
5068c2ecf20Sopenharmony_ci{
5078c2ecf20Sopenharmony_ci	struct hpt_iop_request_set_config *req = hba->u.mv.internal_req;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	memcpy(req, config, sizeof(struct hpt_iop_request_set_config));
5108c2ecf20Sopenharmony_ci	req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
5118c2ecf20Sopenharmony_ci	req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG);
5128c2ecf20Sopenharmony_ci	req->header.size =
5138c2ecf20Sopenharmony_ci		cpu_to_le32(sizeof(struct hpt_iop_request_set_config));
5148c2ecf20Sopenharmony_ci	req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
5158c2ecf20Sopenharmony_ci	req->header.context = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG<<5);
5168c2ecf20Sopenharmony_ci	req->header.context_hi32 = 0;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	if (iop_send_sync_request_mv(hba, 0, 20000)) {
5198c2ecf20Sopenharmony_ci		dprintk("Set config send cmd failed\n");
5208c2ecf20Sopenharmony_ci		return -1;
5218c2ecf20Sopenharmony_ci	}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	return 0;
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_cistatic int iop_set_config_mvfrey(struct hptiop_hba *hba,
5278c2ecf20Sopenharmony_ci				struct hpt_iop_request_set_config *config)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	struct hpt_iop_request_set_config *req =
5308c2ecf20Sopenharmony_ci		hba->u.mvfrey.internal_req.req_virt;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	memcpy(req, config, sizeof(struct hpt_iop_request_set_config));
5338c2ecf20Sopenharmony_ci	req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
5348c2ecf20Sopenharmony_ci	req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG);
5358c2ecf20Sopenharmony_ci	req->header.size =
5368c2ecf20Sopenharmony_ci		cpu_to_le32(sizeof(struct hpt_iop_request_set_config));
5378c2ecf20Sopenharmony_ci	req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
5388c2ecf20Sopenharmony_ci	req->header.context = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG<<5);
5398c2ecf20Sopenharmony_ci	req->header.context_hi32 = 0;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	if (iop_send_sync_request_mvfrey(hba, 0, 20000)) {
5428c2ecf20Sopenharmony_ci		dprintk("Set config send cmd failed\n");
5438c2ecf20Sopenharmony_ci		return -1;
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	return 0;
5478c2ecf20Sopenharmony_ci}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_cistatic void hptiop_enable_intr_itl(struct hptiop_hba *hba)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	writel(~(IOPMU_OUTBOUND_INT_POSTQUEUE | IOPMU_OUTBOUND_INT_MSG0),
5528c2ecf20Sopenharmony_ci		&hba->u.itl.iop->outbound_intmask);
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_cistatic void hptiop_enable_intr_mv(struct hptiop_hba *hba)
5568c2ecf20Sopenharmony_ci{
5578c2ecf20Sopenharmony_ci	writel(MVIOP_MU_OUTBOUND_INT_POSTQUEUE | MVIOP_MU_OUTBOUND_INT_MSG,
5588c2ecf20Sopenharmony_ci		&hba->u.mv.regs->outbound_intmask);
5598c2ecf20Sopenharmony_ci}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_cistatic void hptiop_enable_intr_mvfrey(struct hptiop_hba *hba)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	writel(CPU_TO_F0_DRBL_MSG_BIT, &(hba->u.mvfrey.mu->f0_doorbell_enable));
5648c2ecf20Sopenharmony_ci	writel(0x1, &(hba->u.mvfrey.mu->isr_enable));
5658c2ecf20Sopenharmony_ci	writel(0x1010, &(hba->u.mvfrey.mu->pcie_f0_int_enable));
5668c2ecf20Sopenharmony_ci}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cistatic int hptiop_initialize_iop(struct hptiop_hba *hba)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	/* enable interrupts */
5718c2ecf20Sopenharmony_ci	hba->ops->enable_intr(hba);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	hba->initialized = 1;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	/* start background tasks */
5768c2ecf20Sopenharmony_ci	if (iop_send_sync_msg(hba,
5778c2ecf20Sopenharmony_ci			IOPMU_INBOUND_MSG0_START_BACKGROUND_TASK, 5000)) {
5788c2ecf20Sopenharmony_ci		printk(KERN_ERR "scsi%d: fail to start background task\n",
5798c2ecf20Sopenharmony_ci			hba->host->host_no);
5808c2ecf20Sopenharmony_ci		return -1;
5818c2ecf20Sopenharmony_ci	}
5828c2ecf20Sopenharmony_ci	return 0;
5838c2ecf20Sopenharmony_ci}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_cistatic void __iomem *hptiop_map_pci_bar(struct hptiop_hba *hba, int index)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	u32 mem_base_phy, length;
5888c2ecf20Sopenharmony_ci	void __iomem *mem_base_virt;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	struct pci_dev *pcidev = hba->pcidev;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	if (!(pci_resource_flags(pcidev, index) & IORESOURCE_MEM)) {
5948c2ecf20Sopenharmony_ci		printk(KERN_ERR "scsi%d: pci resource invalid\n",
5958c2ecf20Sopenharmony_ci				hba->host->host_no);
5968c2ecf20Sopenharmony_ci		return NULL;
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	mem_base_phy = pci_resource_start(pcidev, index);
6008c2ecf20Sopenharmony_ci	length = pci_resource_len(pcidev, index);
6018c2ecf20Sopenharmony_ci	mem_base_virt = ioremap(mem_base_phy, length);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	if (!mem_base_virt) {
6048c2ecf20Sopenharmony_ci		printk(KERN_ERR "scsi%d: Fail to ioremap memory space\n",
6058c2ecf20Sopenharmony_ci				hba->host->host_no);
6068c2ecf20Sopenharmony_ci		return NULL;
6078c2ecf20Sopenharmony_ci	}
6088c2ecf20Sopenharmony_ci	return mem_base_virt;
6098c2ecf20Sopenharmony_ci}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_cistatic int hptiop_map_pci_bar_itl(struct hptiop_hba *hba)
6128c2ecf20Sopenharmony_ci{
6138c2ecf20Sopenharmony_ci	struct pci_dev *pcidev = hba->pcidev;
6148c2ecf20Sopenharmony_ci	hba->u.itl.iop = hptiop_map_pci_bar(hba, 0);
6158c2ecf20Sopenharmony_ci	if (hba->u.itl.iop == NULL)
6168c2ecf20Sopenharmony_ci		return -1;
6178c2ecf20Sopenharmony_ci	if ((pcidev->device & 0xff00) == 0x4400) {
6188c2ecf20Sopenharmony_ci		hba->u.itl.plx = hba->u.itl.iop;
6198c2ecf20Sopenharmony_ci		hba->u.itl.iop = hptiop_map_pci_bar(hba, 2);
6208c2ecf20Sopenharmony_ci		if (hba->u.itl.iop == NULL) {
6218c2ecf20Sopenharmony_ci			iounmap(hba->u.itl.plx);
6228c2ecf20Sopenharmony_ci			return -1;
6238c2ecf20Sopenharmony_ci		}
6248c2ecf20Sopenharmony_ci	}
6258c2ecf20Sopenharmony_ci	return 0;
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_cistatic void hptiop_unmap_pci_bar_itl(struct hptiop_hba *hba)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	if (hba->u.itl.plx)
6318c2ecf20Sopenharmony_ci		iounmap(hba->u.itl.plx);
6328c2ecf20Sopenharmony_ci	iounmap(hba->u.itl.iop);
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_cistatic int hptiop_map_pci_bar_mv(struct hptiop_hba *hba)
6368c2ecf20Sopenharmony_ci{
6378c2ecf20Sopenharmony_ci	hba->u.mv.regs = hptiop_map_pci_bar(hba, 0);
6388c2ecf20Sopenharmony_ci	if (hba->u.mv.regs == NULL)
6398c2ecf20Sopenharmony_ci		return -1;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	hba->u.mv.mu = hptiop_map_pci_bar(hba, 2);
6428c2ecf20Sopenharmony_ci	if (hba->u.mv.mu == NULL) {
6438c2ecf20Sopenharmony_ci		iounmap(hba->u.mv.regs);
6448c2ecf20Sopenharmony_ci		return -1;
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	return 0;
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_cistatic int hptiop_map_pci_bar_mvfrey(struct hptiop_hba *hba)
6518c2ecf20Sopenharmony_ci{
6528c2ecf20Sopenharmony_ci	hba->u.mvfrey.config = hptiop_map_pci_bar(hba, 0);
6538c2ecf20Sopenharmony_ci	if (hba->u.mvfrey.config == NULL)
6548c2ecf20Sopenharmony_ci		return -1;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	hba->u.mvfrey.mu = hptiop_map_pci_bar(hba, 2);
6578c2ecf20Sopenharmony_ci	if (hba->u.mvfrey.mu == NULL) {
6588c2ecf20Sopenharmony_ci		iounmap(hba->u.mvfrey.config);
6598c2ecf20Sopenharmony_ci		return -1;
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	return 0;
6638c2ecf20Sopenharmony_ci}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_cistatic void hptiop_unmap_pci_bar_mv(struct hptiop_hba *hba)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	iounmap(hba->u.mv.regs);
6688c2ecf20Sopenharmony_ci	iounmap(hba->u.mv.mu);
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cistatic void hptiop_unmap_pci_bar_mvfrey(struct hptiop_hba *hba)
6728c2ecf20Sopenharmony_ci{
6738c2ecf20Sopenharmony_ci	iounmap(hba->u.mvfrey.config);
6748c2ecf20Sopenharmony_ci	iounmap(hba->u.mvfrey.mu);
6758c2ecf20Sopenharmony_ci}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_cistatic void hptiop_message_callback(struct hptiop_hba *hba, u32 msg)
6788c2ecf20Sopenharmony_ci{
6798c2ecf20Sopenharmony_ci	dprintk("iop message 0x%x\n", msg);
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	if (msg == IOPMU_INBOUND_MSG0_NOP ||
6828c2ecf20Sopenharmony_ci		msg == IOPMU_INBOUND_MSG0_RESET_COMM)
6838c2ecf20Sopenharmony_ci		hba->msg_done = 1;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	if (!hba->initialized)
6868c2ecf20Sopenharmony_ci		return;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	if (msg == IOPMU_INBOUND_MSG0_RESET) {
6898c2ecf20Sopenharmony_ci		atomic_set(&hba->resetting, 0);
6908c2ecf20Sopenharmony_ci		wake_up(&hba->reset_wq);
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci	else if (msg <= IOPMU_INBOUND_MSG0_MAX)
6938c2ecf20Sopenharmony_ci		hba->msg_done = 1;
6948c2ecf20Sopenharmony_ci}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_cistatic struct hptiop_request *get_req(struct hptiop_hba *hba)
6978c2ecf20Sopenharmony_ci{
6988c2ecf20Sopenharmony_ci	struct hptiop_request *ret;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	dprintk("get_req : req=%p\n", hba->req_list);
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	ret = hba->req_list;
7038c2ecf20Sopenharmony_ci	if (ret)
7048c2ecf20Sopenharmony_ci		hba->req_list = ret->next;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	return ret;
7078c2ecf20Sopenharmony_ci}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_cistatic void free_req(struct hptiop_hba *hba, struct hptiop_request *req)
7108c2ecf20Sopenharmony_ci{
7118c2ecf20Sopenharmony_ci	dprintk("free_req(%d, %p)\n", req->index, req);
7128c2ecf20Sopenharmony_ci	req->next = hba->req_list;
7138c2ecf20Sopenharmony_ci	hba->req_list = req;
7148c2ecf20Sopenharmony_ci}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_cistatic void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
7178c2ecf20Sopenharmony_ci				struct hpt_iop_request_scsi_command *req)
7188c2ecf20Sopenharmony_ci{
7198c2ecf20Sopenharmony_ci	struct scsi_cmnd *scp;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	dprintk("hptiop_finish_scsi_req: req=%p, type=%d, "
7228c2ecf20Sopenharmony_ci			"result=%d, context=0x%x tag=%d\n",
7238c2ecf20Sopenharmony_ci			req, req->header.type, req->header.result,
7248c2ecf20Sopenharmony_ci			req->header.context, tag);
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	BUG_ON(!req->header.result);
7278c2ecf20Sopenharmony_ci	BUG_ON(req->header.type != cpu_to_le32(IOP_REQUEST_TYPE_SCSI_COMMAND));
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	scp = hba->reqs[tag].scp;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	if (HPT_SCP(scp)->mapped)
7328c2ecf20Sopenharmony_ci		scsi_dma_unmap(scp);
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	switch (le32_to_cpu(req->header.result)) {
7358c2ecf20Sopenharmony_ci	case IOP_RESULT_SUCCESS:
7368c2ecf20Sopenharmony_ci		scsi_set_resid(scp,
7378c2ecf20Sopenharmony_ci			scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
7388c2ecf20Sopenharmony_ci		scp->result = (DID_OK<<16);
7398c2ecf20Sopenharmony_ci		break;
7408c2ecf20Sopenharmony_ci	case IOP_RESULT_BAD_TARGET:
7418c2ecf20Sopenharmony_ci		scp->result = (DID_BAD_TARGET<<16);
7428c2ecf20Sopenharmony_ci		break;
7438c2ecf20Sopenharmony_ci	case IOP_RESULT_BUSY:
7448c2ecf20Sopenharmony_ci		scp->result = (DID_BUS_BUSY<<16);
7458c2ecf20Sopenharmony_ci		break;
7468c2ecf20Sopenharmony_ci	case IOP_RESULT_RESET:
7478c2ecf20Sopenharmony_ci		scp->result = (DID_RESET<<16);
7488c2ecf20Sopenharmony_ci		break;
7498c2ecf20Sopenharmony_ci	case IOP_RESULT_FAIL:
7508c2ecf20Sopenharmony_ci		scp->result = (DID_ERROR<<16);
7518c2ecf20Sopenharmony_ci		break;
7528c2ecf20Sopenharmony_ci	case IOP_RESULT_INVALID_REQUEST:
7538c2ecf20Sopenharmony_ci		scp->result = (DID_ABORT<<16);
7548c2ecf20Sopenharmony_ci		break;
7558c2ecf20Sopenharmony_ci	case IOP_RESULT_CHECK_CONDITION:
7568c2ecf20Sopenharmony_ci		scsi_set_resid(scp,
7578c2ecf20Sopenharmony_ci			scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
7588c2ecf20Sopenharmony_ci		scp->result = SAM_STAT_CHECK_CONDITION;
7598c2ecf20Sopenharmony_ci		memcpy(scp->sense_buffer, &req->sg_list, SCSI_SENSE_BUFFERSIZE);
7608c2ecf20Sopenharmony_ci		goto skip_resid;
7618c2ecf20Sopenharmony_ci		break;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	default:
7648c2ecf20Sopenharmony_ci		scp->result = DRIVER_INVALID << 24 | DID_ABORT << 16;
7658c2ecf20Sopenharmony_ci		break;
7668c2ecf20Sopenharmony_ci	}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	scsi_set_resid(scp,
7698c2ecf20Sopenharmony_ci		scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ciskip_resid:
7728c2ecf20Sopenharmony_ci	dprintk("scsi_done(%p)\n", scp);
7738c2ecf20Sopenharmony_ci	scp->scsi_done(scp);
7748c2ecf20Sopenharmony_ci	free_req(hba, &hba->reqs[tag]);
7758c2ecf20Sopenharmony_ci}
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_cistatic void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 _tag)
7788c2ecf20Sopenharmony_ci{
7798c2ecf20Sopenharmony_ci	struct hpt_iop_request_scsi_command *req;
7808c2ecf20Sopenharmony_ci	u32 tag;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	if (hba->iopintf_v2) {
7838c2ecf20Sopenharmony_ci		tag = _tag & ~IOPMU_QUEUE_REQUEST_RESULT_BIT;
7848c2ecf20Sopenharmony_ci		req = hba->reqs[tag].req_virt;
7858c2ecf20Sopenharmony_ci		if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT))
7868c2ecf20Sopenharmony_ci			req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS);
7878c2ecf20Sopenharmony_ci	} else {
7888c2ecf20Sopenharmony_ci		tag = _tag;
7898c2ecf20Sopenharmony_ci		req = hba->reqs[tag].req_virt;
7908c2ecf20Sopenharmony_ci	}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	hptiop_finish_scsi_req(hba, tag, req);
7938c2ecf20Sopenharmony_ci}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_cistatic void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag)
7968c2ecf20Sopenharmony_ci{
7978c2ecf20Sopenharmony_ci	struct hpt_iop_request_header __iomem *req;
7988c2ecf20Sopenharmony_ci	struct hpt_iop_request_ioctl_command __iomem *p;
7998c2ecf20Sopenharmony_ci	struct hpt_ioctl_k *arg;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	req = (struct hpt_iop_request_header __iomem *)
8028c2ecf20Sopenharmony_ci			((unsigned long)hba->u.itl.iop + tag);
8038c2ecf20Sopenharmony_ci	dprintk("hptiop_iop_request_callback_itl: req=%p, type=%d, "
8048c2ecf20Sopenharmony_ci			"result=%d, context=0x%x tag=%d\n",
8058c2ecf20Sopenharmony_ci			req, readl(&req->type), readl(&req->result),
8068c2ecf20Sopenharmony_ci			readl(&req->context), tag);
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	BUG_ON(!readl(&req->result));
8098c2ecf20Sopenharmony_ci	BUG_ON(readl(&req->type) != IOP_REQUEST_TYPE_IOCTL_COMMAND);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	p = (struct hpt_iop_request_ioctl_command __iomem *)req;
8128c2ecf20Sopenharmony_ci	arg = (struct hpt_ioctl_k *)(unsigned long)
8138c2ecf20Sopenharmony_ci		(readl(&req->context) |
8148c2ecf20Sopenharmony_ci			((u64)readl(&req->context_hi32)<<32));
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	if (readl(&req->result) == IOP_RESULT_SUCCESS) {
8178c2ecf20Sopenharmony_ci		arg->result = HPT_IOCTL_RESULT_OK;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci		if (arg->outbuf_size)
8208c2ecf20Sopenharmony_ci			memcpy_fromio(arg->outbuf,
8218c2ecf20Sopenharmony_ci				&p->buf[(readl(&p->inbuf_size) + 3)& ~3],
8228c2ecf20Sopenharmony_ci				arg->outbuf_size);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci		if (arg->bytes_returned)
8258c2ecf20Sopenharmony_ci			*arg->bytes_returned = arg->outbuf_size;
8268c2ecf20Sopenharmony_ci	}
8278c2ecf20Sopenharmony_ci	else
8288c2ecf20Sopenharmony_ci		arg->result = HPT_IOCTL_RESULT_FAILED;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	arg->done(arg);
8318c2ecf20Sopenharmony_ci	writel(tag, &hba->u.itl.iop->outbound_queue);
8328c2ecf20Sopenharmony_ci}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_cistatic irqreturn_t hptiop_intr(int irq, void *dev_id)
8358c2ecf20Sopenharmony_ci{
8368c2ecf20Sopenharmony_ci	struct hptiop_hba  *hba = dev_id;
8378c2ecf20Sopenharmony_ci	int  handled;
8388c2ecf20Sopenharmony_ci	unsigned long flags;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	spin_lock_irqsave(hba->host->host_lock, flags);
8418c2ecf20Sopenharmony_ci	handled = hba->ops->iop_intr(hba);
8428c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(hba->host->host_lock, flags);
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	return handled;
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_cistatic int hptiop_buildsgl(struct scsi_cmnd *scp, struct hpt_iopsg *psg)
8488c2ecf20Sopenharmony_ci{
8498c2ecf20Sopenharmony_ci	struct Scsi_Host *host = scp->device->host;
8508c2ecf20Sopenharmony_ci	struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
8518c2ecf20Sopenharmony_ci	struct scatterlist *sg;
8528c2ecf20Sopenharmony_ci	int idx, nseg;
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	nseg = scsi_dma_map(scp);
8558c2ecf20Sopenharmony_ci	BUG_ON(nseg < 0);
8568c2ecf20Sopenharmony_ci	if (!nseg)
8578c2ecf20Sopenharmony_ci		return 0;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	HPT_SCP(scp)->sgcnt = nseg;
8608c2ecf20Sopenharmony_ci	HPT_SCP(scp)->mapped = 1;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	BUG_ON(HPT_SCP(scp)->sgcnt > hba->max_sg_descriptors);
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	scsi_for_each_sg(scp, sg, HPT_SCP(scp)->sgcnt, idx) {
8658c2ecf20Sopenharmony_ci		psg[idx].pci_address = cpu_to_le64(sg_dma_address(sg)) |
8668c2ecf20Sopenharmony_ci			hba->ops->host_phy_flag;
8678c2ecf20Sopenharmony_ci		psg[idx].size = cpu_to_le32(sg_dma_len(sg));
8688c2ecf20Sopenharmony_ci		psg[idx].eot = (idx == HPT_SCP(scp)->sgcnt - 1) ?
8698c2ecf20Sopenharmony_ci			cpu_to_le32(1) : 0;
8708c2ecf20Sopenharmony_ci	}
8718c2ecf20Sopenharmony_ci	return HPT_SCP(scp)->sgcnt;
8728c2ecf20Sopenharmony_ci}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_cistatic void hptiop_post_req_itl(struct hptiop_hba *hba,
8758c2ecf20Sopenharmony_ci					struct hptiop_request *_req)
8768c2ecf20Sopenharmony_ci{
8778c2ecf20Sopenharmony_ci	struct hpt_iop_request_header *reqhdr = _req->req_virt;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	reqhdr->context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT |
8808c2ecf20Sopenharmony_ci							(u32)_req->index);
8818c2ecf20Sopenharmony_ci	reqhdr->context_hi32 = 0;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	if (hba->iopintf_v2) {
8848c2ecf20Sopenharmony_ci		u32 size, size_bits;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci		size = le32_to_cpu(reqhdr->size);
8878c2ecf20Sopenharmony_ci		if (size < 256)
8888c2ecf20Sopenharmony_ci			size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
8898c2ecf20Sopenharmony_ci		else if (size < 512)
8908c2ecf20Sopenharmony_ci			size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
8918c2ecf20Sopenharmony_ci		else
8928c2ecf20Sopenharmony_ci			size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT |
8938c2ecf20Sopenharmony_ci						IOPMU_QUEUE_ADDR_HOST_BIT;
8948c2ecf20Sopenharmony_ci		writel(_req->req_shifted_phy | size_bits,
8958c2ecf20Sopenharmony_ci			&hba->u.itl.iop->inbound_queue);
8968c2ecf20Sopenharmony_ci	} else
8978c2ecf20Sopenharmony_ci		writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT,
8988c2ecf20Sopenharmony_ci					&hba->u.itl.iop->inbound_queue);
8998c2ecf20Sopenharmony_ci}
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_cistatic void hptiop_post_req_mv(struct hptiop_hba *hba,
9028c2ecf20Sopenharmony_ci					struct hptiop_request *_req)
9038c2ecf20Sopenharmony_ci{
9048c2ecf20Sopenharmony_ci	struct hpt_iop_request_header *reqhdr = _req->req_virt;
9058c2ecf20Sopenharmony_ci	u32 size, size_bit;
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	reqhdr->context = cpu_to_le32(_req->index<<8 |
9088c2ecf20Sopenharmony_ci					IOP_REQUEST_TYPE_SCSI_COMMAND<<5);
9098c2ecf20Sopenharmony_ci	reqhdr->context_hi32 = 0;
9108c2ecf20Sopenharmony_ci	size = le32_to_cpu(reqhdr->size);
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	if (size <= 256)
9138c2ecf20Sopenharmony_ci		size_bit = 0;
9148c2ecf20Sopenharmony_ci	else if (size <= 256*2)
9158c2ecf20Sopenharmony_ci		size_bit = 1;
9168c2ecf20Sopenharmony_ci	else if (size <= 256*3)
9178c2ecf20Sopenharmony_ci		size_bit = 2;
9188c2ecf20Sopenharmony_ci	else
9198c2ecf20Sopenharmony_ci		size_bit = 3;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	mv_inbound_write((_req->req_shifted_phy << 5) |
9228c2ecf20Sopenharmony_ci		MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bit, hba);
9238c2ecf20Sopenharmony_ci}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_cistatic void hptiop_post_req_mvfrey(struct hptiop_hba *hba,
9268c2ecf20Sopenharmony_ci					struct hptiop_request *_req)
9278c2ecf20Sopenharmony_ci{
9288c2ecf20Sopenharmony_ci	struct hpt_iop_request_header *reqhdr = _req->req_virt;
9298c2ecf20Sopenharmony_ci	u32 index;
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	reqhdr->flags |= cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT |
9328c2ecf20Sopenharmony_ci			IOP_REQUEST_FLAG_ADDR_BITS |
9338c2ecf20Sopenharmony_ci			((_req->req_shifted_phy >> 11) & 0xffff0000));
9348c2ecf20Sopenharmony_ci	reqhdr->context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT |
9358c2ecf20Sopenharmony_ci			(_req->index << 4) | reqhdr->type);
9368c2ecf20Sopenharmony_ci	reqhdr->context_hi32 = cpu_to_le32((_req->req_shifted_phy << 5) &
9378c2ecf20Sopenharmony_ci			0xffffffff);
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	hba->u.mvfrey.inlist_wptr++;
9408c2ecf20Sopenharmony_ci	index = hba->u.mvfrey.inlist_wptr & 0x3fff;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	if (index == hba->u.mvfrey.list_count) {
9438c2ecf20Sopenharmony_ci		index = 0;
9448c2ecf20Sopenharmony_ci		hba->u.mvfrey.inlist_wptr &= ~0x3fff;
9458c2ecf20Sopenharmony_ci		hba->u.mvfrey.inlist_wptr ^= CL_POINTER_TOGGLE;
9468c2ecf20Sopenharmony_ci	}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	hba->u.mvfrey.inlist[index].addr =
9498c2ecf20Sopenharmony_ci			(dma_addr_t)_req->req_shifted_phy << 5;
9508c2ecf20Sopenharmony_ci	hba->u.mvfrey.inlist[index].intrfc_len = (reqhdr->size + 3) / 4;
9518c2ecf20Sopenharmony_ci	writel(hba->u.mvfrey.inlist_wptr,
9528c2ecf20Sopenharmony_ci		&(hba->u.mvfrey.mu->inbound_write_ptr));
9538c2ecf20Sopenharmony_ci	readl(&(hba->u.mvfrey.mu->inbound_write_ptr));
9548c2ecf20Sopenharmony_ci}
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_cistatic int hptiop_reset_comm_itl(struct hptiop_hba *hba)
9578c2ecf20Sopenharmony_ci{
9588c2ecf20Sopenharmony_ci	return 0;
9598c2ecf20Sopenharmony_ci}
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_cistatic int hptiop_reset_comm_mv(struct hptiop_hba *hba)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	return 0;
9648c2ecf20Sopenharmony_ci}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_cistatic int hptiop_reset_comm_mvfrey(struct hptiop_hba *hba)
9678c2ecf20Sopenharmony_ci{
9688c2ecf20Sopenharmony_ci	u32 list_count = hba->u.mvfrey.list_count;
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	if (iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_RESET_COMM, 3000))
9718c2ecf20Sopenharmony_ci		return -1;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	/* wait 100ms for MCU ready */
9748c2ecf20Sopenharmony_ci	msleep(100);
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	writel(cpu_to_le32(hba->u.mvfrey.inlist_phy & 0xffffffff),
9778c2ecf20Sopenharmony_ci			&(hba->u.mvfrey.mu->inbound_base));
9788c2ecf20Sopenharmony_ci	writel(cpu_to_le32((hba->u.mvfrey.inlist_phy >> 16) >> 16),
9798c2ecf20Sopenharmony_ci			&(hba->u.mvfrey.mu->inbound_base_high));
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	writel(cpu_to_le32(hba->u.mvfrey.outlist_phy & 0xffffffff),
9828c2ecf20Sopenharmony_ci			&(hba->u.mvfrey.mu->outbound_base));
9838c2ecf20Sopenharmony_ci	writel(cpu_to_le32((hba->u.mvfrey.outlist_phy >> 16) >> 16),
9848c2ecf20Sopenharmony_ci			&(hba->u.mvfrey.mu->outbound_base_high));
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	writel(cpu_to_le32(hba->u.mvfrey.outlist_cptr_phy & 0xffffffff),
9878c2ecf20Sopenharmony_ci			&(hba->u.mvfrey.mu->outbound_shadow_base));
9888c2ecf20Sopenharmony_ci	writel(cpu_to_le32((hba->u.mvfrey.outlist_cptr_phy >> 16) >> 16),
9898c2ecf20Sopenharmony_ci			&(hba->u.mvfrey.mu->outbound_shadow_base_high));
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	hba->u.mvfrey.inlist_wptr = (list_count - 1) | CL_POINTER_TOGGLE;
9928c2ecf20Sopenharmony_ci	*hba->u.mvfrey.outlist_cptr = (list_count - 1) | CL_POINTER_TOGGLE;
9938c2ecf20Sopenharmony_ci	hba->u.mvfrey.outlist_rptr = list_count - 1;
9948c2ecf20Sopenharmony_ci	return 0;
9958c2ecf20Sopenharmony_ci}
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_cistatic int hptiop_queuecommand_lck(struct scsi_cmnd *scp,
9988c2ecf20Sopenharmony_ci				void (*done)(struct scsi_cmnd *))
9998c2ecf20Sopenharmony_ci{
10008c2ecf20Sopenharmony_ci	struct Scsi_Host *host = scp->device->host;
10018c2ecf20Sopenharmony_ci	struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
10028c2ecf20Sopenharmony_ci	struct hpt_iop_request_scsi_command *req;
10038c2ecf20Sopenharmony_ci	int sg_count = 0;
10048c2ecf20Sopenharmony_ci	struct hptiop_request *_req;
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	BUG_ON(!done);
10078c2ecf20Sopenharmony_ci	scp->scsi_done = done;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	_req = get_req(hba);
10108c2ecf20Sopenharmony_ci	if (_req == NULL) {
10118c2ecf20Sopenharmony_ci		dprintk("hptiop_queuecmd : no free req\n");
10128c2ecf20Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
10138c2ecf20Sopenharmony_ci	}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	_req->scp = scp;
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	dprintk("hptiop_queuecmd(scp=%p) %d/%d/%d/%llu cdb=(%08x-%08x-%08x-%08x) "
10188c2ecf20Sopenharmony_ci			"req_index=%d, req=%p\n",
10198c2ecf20Sopenharmony_ci			scp,
10208c2ecf20Sopenharmony_ci			host->host_no, scp->device->channel,
10218c2ecf20Sopenharmony_ci			scp->device->id, scp->device->lun,
10228c2ecf20Sopenharmony_ci			cpu_to_be32(((u32 *)scp->cmnd)[0]),
10238c2ecf20Sopenharmony_ci			cpu_to_be32(((u32 *)scp->cmnd)[1]),
10248c2ecf20Sopenharmony_ci			cpu_to_be32(((u32 *)scp->cmnd)[2]),
10258c2ecf20Sopenharmony_ci			cpu_to_be32(((u32 *)scp->cmnd)[3]),
10268c2ecf20Sopenharmony_ci			_req->index, _req->req_virt);
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	scp->result = 0;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	if (scp->device->channel ||
10318c2ecf20Sopenharmony_ci			(scp->device->id > hba->max_devices) ||
10328c2ecf20Sopenharmony_ci			((scp->device->id == (hba->max_devices-1)) && scp->device->lun)) {
10338c2ecf20Sopenharmony_ci		scp->result = DID_BAD_TARGET << 16;
10348c2ecf20Sopenharmony_ci		free_req(hba, _req);
10358c2ecf20Sopenharmony_ci		goto cmd_done;
10368c2ecf20Sopenharmony_ci	}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	req = _req->req_virt;
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	/* build S/G table */
10418c2ecf20Sopenharmony_ci	sg_count = hptiop_buildsgl(scp, req->sg_list);
10428c2ecf20Sopenharmony_ci	if (!sg_count)
10438c2ecf20Sopenharmony_ci		HPT_SCP(scp)->mapped = 0;
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
10468c2ecf20Sopenharmony_ci	req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SCSI_COMMAND);
10478c2ecf20Sopenharmony_ci	req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
10488c2ecf20Sopenharmony_ci	req->dataxfer_length = cpu_to_le32(scsi_bufflen(scp));
10498c2ecf20Sopenharmony_ci	req->channel = scp->device->channel;
10508c2ecf20Sopenharmony_ci	req->target = scp->device->id;
10518c2ecf20Sopenharmony_ci	req->lun = scp->device->lun;
10528c2ecf20Sopenharmony_ci	req->header.size = cpu_to_le32(
10538c2ecf20Sopenharmony_ci				sizeof(struct hpt_iop_request_scsi_command)
10548c2ecf20Sopenharmony_ci				 - sizeof(struct hpt_iopsg)
10558c2ecf20Sopenharmony_ci				 + sg_count * sizeof(struct hpt_iopsg));
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	memcpy(req->cdb, scp->cmnd, sizeof(req->cdb));
10588c2ecf20Sopenharmony_ci	hba->ops->post_req(hba, _req);
10598c2ecf20Sopenharmony_ci	return 0;
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_cicmd_done:
10628c2ecf20Sopenharmony_ci	dprintk("scsi_done(scp=%p)\n", scp);
10638c2ecf20Sopenharmony_ci	scp->scsi_done(scp);
10648c2ecf20Sopenharmony_ci	return 0;
10658c2ecf20Sopenharmony_ci}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(hptiop_queuecommand)
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_cistatic const char *hptiop_info(struct Scsi_Host *host)
10708c2ecf20Sopenharmony_ci{
10718c2ecf20Sopenharmony_ci	return driver_name_long;
10728c2ecf20Sopenharmony_ci}
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_cistatic int hptiop_reset_hba(struct hptiop_hba *hba)
10758c2ecf20Sopenharmony_ci{
10768c2ecf20Sopenharmony_ci	if (atomic_xchg(&hba->resetting, 1) == 0) {
10778c2ecf20Sopenharmony_ci		atomic_inc(&hba->reset_count);
10788c2ecf20Sopenharmony_ci		hba->ops->post_msg(hba, IOPMU_INBOUND_MSG0_RESET);
10798c2ecf20Sopenharmony_ci	}
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	wait_event_timeout(hba->reset_wq,
10828c2ecf20Sopenharmony_ci			atomic_read(&hba->resetting) == 0, 60 * HZ);
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	if (atomic_read(&hba->resetting)) {
10858c2ecf20Sopenharmony_ci		/* IOP is in unknown state, abort reset */
10868c2ecf20Sopenharmony_ci		printk(KERN_ERR "scsi%d: reset failed\n", hba->host->host_no);
10878c2ecf20Sopenharmony_ci		return -1;
10888c2ecf20Sopenharmony_ci	}
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	if (iop_send_sync_msg(hba,
10918c2ecf20Sopenharmony_ci		IOPMU_INBOUND_MSG0_START_BACKGROUND_TASK, 5000)) {
10928c2ecf20Sopenharmony_ci		dprintk("scsi%d: fail to start background task\n",
10938c2ecf20Sopenharmony_ci				hba->host->host_no);
10948c2ecf20Sopenharmony_ci	}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	return 0;
10978c2ecf20Sopenharmony_ci}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_cistatic int hptiop_reset(struct scsi_cmnd *scp)
11008c2ecf20Sopenharmony_ci{
11018c2ecf20Sopenharmony_ci	struct hptiop_hba * hba = (struct hptiop_hba *)scp->device->host->hostdata;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	printk(KERN_WARNING "hptiop_reset(%d/%d/%d)\n",
11048c2ecf20Sopenharmony_ci	       scp->device->host->host_no, -1, -1);
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	return hptiop_reset_hba(hba)? FAILED : SUCCESS;
11078c2ecf20Sopenharmony_ci}
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_cistatic int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev,
11108c2ecf20Sopenharmony_ci					  int queue_depth)
11118c2ecf20Sopenharmony_ci{
11128c2ecf20Sopenharmony_ci	struct hptiop_hba *hba = (struct hptiop_hba *)sdev->host->hostdata;
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	if (queue_depth > hba->max_requests)
11158c2ecf20Sopenharmony_ci		queue_depth = hba->max_requests;
11168c2ecf20Sopenharmony_ci	return scsi_change_queue_depth(sdev, queue_depth);
11178c2ecf20Sopenharmony_ci}
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_cistatic ssize_t hptiop_show_version(struct device *dev,
11208c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
11218c2ecf20Sopenharmony_ci{
11228c2ecf20Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%s\n", driver_ver);
11238c2ecf20Sopenharmony_ci}
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_cistatic ssize_t hptiop_show_fw_version(struct device *dev,
11268c2ecf20Sopenharmony_ci				      struct device_attribute *attr, char *buf)
11278c2ecf20Sopenharmony_ci{
11288c2ecf20Sopenharmony_ci	struct Scsi_Host *host = class_to_shost(dev);
11298c2ecf20Sopenharmony_ci	struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n",
11328c2ecf20Sopenharmony_ci				hba->firmware_version >> 24,
11338c2ecf20Sopenharmony_ci				(hba->firmware_version >> 16) & 0xff,
11348c2ecf20Sopenharmony_ci				(hba->firmware_version >> 8) & 0xff,
11358c2ecf20Sopenharmony_ci				hba->firmware_version & 0xff);
11368c2ecf20Sopenharmony_ci}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_cistatic struct device_attribute hptiop_attr_version = {
11398c2ecf20Sopenharmony_ci	.attr = {
11408c2ecf20Sopenharmony_ci		.name = "driver-version",
11418c2ecf20Sopenharmony_ci		.mode = S_IRUGO,
11428c2ecf20Sopenharmony_ci	},
11438c2ecf20Sopenharmony_ci	.show = hptiop_show_version,
11448c2ecf20Sopenharmony_ci};
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_cistatic struct device_attribute hptiop_attr_fw_version = {
11478c2ecf20Sopenharmony_ci	.attr = {
11488c2ecf20Sopenharmony_ci		.name = "firmware-version",
11498c2ecf20Sopenharmony_ci		.mode = S_IRUGO,
11508c2ecf20Sopenharmony_ci	},
11518c2ecf20Sopenharmony_ci	.show = hptiop_show_fw_version,
11528c2ecf20Sopenharmony_ci};
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_cistatic struct device_attribute *hptiop_attrs[] = {
11558c2ecf20Sopenharmony_ci	&hptiop_attr_version,
11568c2ecf20Sopenharmony_ci	&hptiop_attr_fw_version,
11578c2ecf20Sopenharmony_ci	NULL
11588c2ecf20Sopenharmony_ci};
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_cistatic int hptiop_slave_config(struct scsi_device *sdev)
11618c2ecf20Sopenharmony_ci{
11628c2ecf20Sopenharmony_ci	if (sdev->type == TYPE_TAPE)
11638c2ecf20Sopenharmony_ci		blk_queue_max_hw_sectors(sdev->request_queue, 8192);
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	return 0;
11668c2ecf20Sopenharmony_ci}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_cistatic struct scsi_host_template driver_template = {
11698c2ecf20Sopenharmony_ci	.module                     = THIS_MODULE,
11708c2ecf20Sopenharmony_ci	.name                       = driver_name,
11718c2ecf20Sopenharmony_ci	.queuecommand               = hptiop_queuecommand,
11728c2ecf20Sopenharmony_ci	.eh_host_reset_handler      = hptiop_reset,
11738c2ecf20Sopenharmony_ci	.info                       = hptiop_info,
11748c2ecf20Sopenharmony_ci	.emulated                   = 0,
11758c2ecf20Sopenharmony_ci	.proc_name                  = driver_name,
11768c2ecf20Sopenharmony_ci	.shost_attrs                = hptiop_attrs,
11778c2ecf20Sopenharmony_ci	.slave_configure            = hptiop_slave_config,
11788c2ecf20Sopenharmony_ci	.this_id                    = -1,
11798c2ecf20Sopenharmony_ci	.change_queue_depth         = hptiop_adjust_disk_queue_depth,
11808c2ecf20Sopenharmony_ci};
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_cistatic int hptiop_internal_memalloc_itl(struct hptiop_hba *hba)
11838c2ecf20Sopenharmony_ci{
11848c2ecf20Sopenharmony_ci	return 0;
11858c2ecf20Sopenharmony_ci}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_cistatic int hptiop_internal_memalloc_mv(struct hptiop_hba *hba)
11888c2ecf20Sopenharmony_ci{
11898c2ecf20Sopenharmony_ci	hba->u.mv.internal_req = dma_alloc_coherent(&hba->pcidev->dev,
11908c2ecf20Sopenharmony_ci			0x800, &hba->u.mv.internal_req_phy, GFP_KERNEL);
11918c2ecf20Sopenharmony_ci	if (hba->u.mv.internal_req)
11928c2ecf20Sopenharmony_ci		return 0;
11938c2ecf20Sopenharmony_ci	else
11948c2ecf20Sopenharmony_ci		return -1;
11958c2ecf20Sopenharmony_ci}
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_cistatic int hptiop_internal_memalloc_mvfrey(struct hptiop_hba *hba)
11988c2ecf20Sopenharmony_ci{
11998c2ecf20Sopenharmony_ci	u32 list_count = readl(&hba->u.mvfrey.mu->inbound_conf_ctl);
12008c2ecf20Sopenharmony_ci	char *p;
12018c2ecf20Sopenharmony_ci	dma_addr_t phy;
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	BUG_ON(hba->max_request_size == 0);
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	if (list_count == 0) {
12068c2ecf20Sopenharmony_ci		BUG_ON(1);
12078c2ecf20Sopenharmony_ci		return -1;
12088c2ecf20Sopenharmony_ci	}
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	list_count >>= 16;
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	hba->u.mvfrey.list_count = list_count;
12138c2ecf20Sopenharmony_ci	hba->u.mvfrey.internal_mem_size = 0x800 +
12148c2ecf20Sopenharmony_ci			list_count * sizeof(struct mvfrey_inlist_entry) +
12158c2ecf20Sopenharmony_ci			list_count * sizeof(struct mvfrey_outlist_entry) +
12168c2ecf20Sopenharmony_ci			sizeof(int);
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	p = dma_alloc_coherent(&hba->pcidev->dev,
12198c2ecf20Sopenharmony_ci			hba->u.mvfrey.internal_mem_size, &phy, GFP_KERNEL);
12208c2ecf20Sopenharmony_ci	if (!p)
12218c2ecf20Sopenharmony_ci		return -1;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	hba->u.mvfrey.internal_req.req_virt = p;
12248c2ecf20Sopenharmony_ci	hba->u.mvfrey.internal_req.req_shifted_phy = phy >> 5;
12258c2ecf20Sopenharmony_ci	hba->u.mvfrey.internal_req.scp = NULL;
12268c2ecf20Sopenharmony_ci	hba->u.mvfrey.internal_req.next = NULL;
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	p += 0x800;
12298c2ecf20Sopenharmony_ci	phy += 0x800;
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	hba->u.mvfrey.inlist = (struct mvfrey_inlist_entry *)p;
12328c2ecf20Sopenharmony_ci	hba->u.mvfrey.inlist_phy = phy;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	p += list_count * sizeof(struct mvfrey_inlist_entry);
12358c2ecf20Sopenharmony_ci	phy += list_count * sizeof(struct mvfrey_inlist_entry);
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	hba->u.mvfrey.outlist = (struct mvfrey_outlist_entry *)p;
12388c2ecf20Sopenharmony_ci	hba->u.mvfrey.outlist_phy = phy;
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	p += list_count * sizeof(struct mvfrey_outlist_entry);
12418c2ecf20Sopenharmony_ci	phy += list_count * sizeof(struct mvfrey_outlist_entry);
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	hba->u.mvfrey.outlist_cptr = (__le32 *)p;
12448c2ecf20Sopenharmony_ci	hba->u.mvfrey.outlist_cptr_phy = phy;
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	return 0;
12478c2ecf20Sopenharmony_ci}
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_cistatic int hptiop_internal_memfree_itl(struct hptiop_hba *hba)
12508c2ecf20Sopenharmony_ci{
12518c2ecf20Sopenharmony_ci	return 0;
12528c2ecf20Sopenharmony_ci}
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_cistatic int hptiop_internal_memfree_mv(struct hptiop_hba *hba)
12558c2ecf20Sopenharmony_ci{
12568c2ecf20Sopenharmony_ci	if (hba->u.mv.internal_req) {
12578c2ecf20Sopenharmony_ci		dma_free_coherent(&hba->pcidev->dev, 0x800,
12588c2ecf20Sopenharmony_ci			hba->u.mv.internal_req, hba->u.mv.internal_req_phy);
12598c2ecf20Sopenharmony_ci		return 0;
12608c2ecf20Sopenharmony_ci	} else
12618c2ecf20Sopenharmony_ci		return -1;
12628c2ecf20Sopenharmony_ci}
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_cistatic int hptiop_internal_memfree_mvfrey(struct hptiop_hba *hba)
12658c2ecf20Sopenharmony_ci{
12668c2ecf20Sopenharmony_ci	if (hba->u.mvfrey.internal_req.req_virt) {
12678c2ecf20Sopenharmony_ci		dma_free_coherent(&hba->pcidev->dev,
12688c2ecf20Sopenharmony_ci			hba->u.mvfrey.internal_mem_size,
12698c2ecf20Sopenharmony_ci			hba->u.mvfrey.internal_req.req_virt,
12708c2ecf20Sopenharmony_ci			(dma_addr_t)
12718c2ecf20Sopenharmony_ci			hba->u.mvfrey.internal_req.req_shifted_phy << 5);
12728c2ecf20Sopenharmony_ci		return 0;
12738c2ecf20Sopenharmony_ci	} else
12748c2ecf20Sopenharmony_ci		return -1;
12758c2ecf20Sopenharmony_ci}
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_cistatic int hptiop_probe(struct pci_dev *pcidev, const struct pci_device_id *id)
12788c2ecf20Sopenharmony_ci{
12798c2ecf20Sopenharmony_ci	struct Scsi_Host *host = NULL;
12808c2ecf20Sopenharmony_ci	struct hptiop_hba *hba;
12818c2ecf20Sopenharmony_ci	struct hptiop_adapter_ops *iop_ops;
12828c2ecf20Sopenharmony_ci	struct hpt_iop_request_get_config iop_config;
12838c2ecf20Sopenharmony_ci	struct hpt_iop_request_set_config set_config;
12848c2ecf20Sopenharmony_ci	dma_addr_t start_phy;
12858c2ecf20Sopenharmony_ci	void *start_virt;
12868c2ecf20Sopenharmony_ci	u32 offset, i, req_size;
12878c2ecf20Sopenharmony_ci	int rc;
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	dprintk("hptiop_probe(%p)\n", pcidev);
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci	if (pci_enable_device(pcidev)) {
12928c2ecf20Sopenharmony_ci		printk(KERN_ERR "hptiop: fail to enable pci device\n");
12938c2ecf20Sopenharmony_ci		return -ENODEV;
12948c2ecf20Sopenharmony_ci	}
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	printk(KERN_INFO "adapter at PCI %d:%d:%d, IRQ %d\n",
12978c2ecf20Sopenharmony_ci		pcidev->bus->number, pcidev->devfn >> 3, pcidev->devfn & 7,
12988c2ecf20Sopenharmony_ci		pcidev->irq);
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	pci_set_master(pcidev);
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	/* Enable 64bit DMA if possible */
13038c2ecf20Sopenharmony_ci	iop_ops = (struct hptiop_adapter_ops *)id->driver_data;
13048c2ecf20Sopenharmony_ci	rc = dma_set_mask(&pcidev->dev,
13058c2ecf20Sopenharmony_ci			  DMA_BIT_MASK(iop_ops->hw_dma_bit_mask));
13068c2ecf20Sopenharmony_ci	if (rc)
13078c2ecf20Sopenharmony_ci		rc = dma_set_mask(&pcidev->dev, DMA_BIT_MASK(32));
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	if (rc) {
13108c2ecf20Sopenharmony_ci		printk(KERN_ERR "hptiop: fail to set dma_mask\n");
13118c2ecf20Sopenharmony_ci		goto disable_pci_device;
13128c2ecf20Sopenharmony_ci	}
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	if (pci_request_regions(pcidev, driver_name)) {
13158c2ecf20Sopenharmony_ci		printk(KERN_ERR "hptiop: pci_request_regions failed\n");
13168c2ecf20Sopenharmony_ci		goto disable_pci_device;
13178c2ecf20Sopenharmony_ci	}
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	host = scsi_host_alloc(&driver_template, sizeof(struct hptiop_hba));
13208c2ecf20Sopenharmony_ci	if (!host) {
13218c2ecf20Sopenharmony_ci		printk(KERN_ERR "hptiop: fail to alloc scsi host\n");
13228c2ecf20Sopenharmony_ci		goto free_pci_regions;
13238c2ecf20Sopenharmony_ci	}
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	hba = (struct hptiop_hba *)host->hostdata;
13268c2ecf20Sopenharmony_ci	memset(hba, 0, sizeof(struct hptiop_hba));
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	hba->ops = iop_ops;
13298c2ecf20Sopenharmony_ci	hba->pcidev = pcidev;
13308c2ecf20Sopenharmony_ci	hba->host = host;
13318c2ecf20Sopenharmony_ci	hba->initialized = 0;
13328c2ecf20Sopenharmony_ci	hba->iopintf_v2 = 0;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	atomic_set(&hba->resetting, 0);
13358c2ecf20Sopenharmony_ci	atomic_set(&hba->reset_count, 0);
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	init_waitqueue_head(&hba->reset_wq);
13388c2ecf20Sopenharmony_ci	init_waitqueue_head(&hba->ioctl_wq);
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	host->max_lun = 128;
13418c2ecf20Sopenharmony_ci	host->max_channel = 0;
13428c2ecf20Sopenharmony_ci	host->io_port = 0;
13438c2ecf20Sopenharmony_ci	host->n_io_port = 0;
13448c2ecf20Sopenharmony_ci	host->irq = pcidev->irq;
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_ci	if (hba->ops->map_pci_bar(hba))
13478c2ecf20Sopenharmony_ci		goto free_scsi_host;
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	if (hba->ops->iop_wait_ready(hba, 20000)) {
13508c2ecf20Sopenharmony_ci		printk(KERN_ERR "scsi%d: firmware not ready\n",
13518c2ecf20Sopenharmony_ci				hba->host->host_no);
13528c2ecf20Sopenharmony_ci		goto unmap_pci_bar;
13538c2ecf20Sopenharmony_ci	}
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	if (hba->ops->family == MV_BASED_IOP) {
13568c2ecf20Sopenharmony_ci		if (hba->ops->internal_memalloc(hba)) {
13578c2ecf20Sopenharmony_ci			printk(KERN_ERR "scsi%d: internal_memalloc failed\n",
13588c2ecf20Sopenharmony_ci				hba->host->host_no);
13598c2ecf20Sopenharmony_ci			goto unmap_pci_bar;
13608c2ecf20Sopenharmony_ci		}
13618c2ecf20Sopenharmony_ci	}
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	if (hba->ops->get_config(hba, &iop_config)) {
13648c2ecf20Sopenharmony_ci		printk(KERN_ERR "scsi%d: get config failed\n",
13658c2ecf20Sopenharmony_ci				hba->host->host_no);
13668c2ecf20Sopenharmony_ci		goto unmap_pci_bar;
13678c2ecf20Sopenharmony_ci	}
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	hba->max_requests = min(le32_to_cpu(iop_config.max_requests),
13708c2ecf20Sopenharmony_ci				HPTIOP_MAX_REQUESTS);
13718c2ecf20Sopenharmony_ci	hba->max_devices = le32_to_cpu(iop_config.max_devices);
13728c2ecf20Sopenharmony_ci	hba->max_request_size = le32_to_cpu(iop_config.request_size);
13738c2ecf20Sopenharmony_ci	hba->max_sg_descriptors = le32_to_cpu(iop_config.max_sg_count);
13748c2ecf20Sopenharmony_ci	hba->firmware_version = le32_to_cpu(iop_config.firmware_version);
13758c2ecf20Sopenharmony_ci	hba->interface_version = le32_to_cpu(iop_config.interface_version);
13768c2ecf20Sopenharmony_ci	hba->sdram_size = le32_to_cpu(iop_config.sdram_size);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	if (hba->ops->family == MVFREY_BASED_IOP) {
13798c2ecf20Sopenharmony_ci		if (hba->ops->internal_memalloc(hba)) {
13808c2ecf20Sopenharmony_ci			printk(KERN_ERR "scsi%d: internal_memalloc failed\n",
13818c2ecf20Sopenharmony_ci				hba->host->host_no);
13828c2ecf20Sopenharmony_ci			goto unmap_pci_bar;
13838c2ecf20Sopenharmony_ci		}
13848c2ecf20Sopenharmony_ci		if (hba->ops->reset_comm(hba)) {
13858c2ecf20Sopenharmony_ci			printk(KERN_ERR "scsi%d: reset comm failed\n",
13868c2ecf20Sopenharmony_ci					hba->host->host_no);
13878c2ecf20Sopenharmony_ci			goto unmap_pci_bar;
13888c2ecf20Sopenharmony_ci		}
13898c2ecf20Sopenharmony_ci	}
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	if (hba->firmware_version > 0x01020000 ||
13928c2ecf20Sopenharmony_ci			hba->interface_version > 0x01020000)
13938c2ecf20Sopenharmony_ci		hba->iopintf_v2 = 1;
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	host->max_sectors = le32_to_cpu(iop_config.data_transfer_length) >> 9;
13968c2ecf20Sopenharmony_ci	host->max_id = le32_to_cpu(iop_config.max_devices);
13978c2ecf20Sopenharmony_ci	host->sg_tablesize = le32_to_cpu(iop_config.max_sg_count);
13988c2ecf20Sopenharmony_ci	host->can_queue = le32_to_cpu(iop_config.max_requests);
13998c2ecf20Sopenharmony_ci	host->cmd_per_lun = le32_to_cpu(iop_config.max_requests);
14008c2ecf20Sopenharmony_ci	host->max_cmd_len = 16;
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	req_size = sizeof(struct hpt_iop_request_scsi_command)
14038c2ecf20Sopenharmony_ci		+ sizeof(struct hpt_iopsg) * (hba->max_sg_descriptors - 1);
14048c2ecf20Sopenharmony_ci	if ((req_size & 0x1f) != 0)
14058c2ecf20Sopenharmony_ci		req_size = (req_size + 0x1f) & ~0x1f;
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	memset(&set_config, 0, sizeof(struct hpt_iop_request_set_config));
14088c2ecf20Sopenharmony_ci	set_config.iop_id = cpu_to_le32(host->host_no);
14098c2ecf20Sopenharmony_ci	set_config.vbus_id = cpu_to_le16(host->host_no);
14108c2ecf20Sopenharmony_ci	set_config.max_host_request_size = cpu_to_le16(req_size);
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	if (hba->ops->set_config(hba, &set_config)) {
14138c2ecf20Sopenharmony_ci		printk(KERN_ERR "scsi%d: set config failed\n",
14148c2ecf20Sopenharmony_ci				hba->host->host_no);
14158c2ecf20Sopenharmony_ci		goto unmap_pci_bar;
14168c2ecf20Sopenharmony_ci	}
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	pci_set_drvdata(pcidev, host);
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	if (request_irq(pcidev->irq, hptiop_intr, IRQF_SHARED,
14218c2ecf20Sopenharmony_ci					driver_name, hba)) {
14228c2ecf20Sopenharmony_ci		printk(KERN_ERR "scsi%d: request irq %d failed\n",
14238c2ecf20Sopenharmony_ci					hba->host->host_no, pcidev->irq);
14248c2ecf20Sopenharmony_ci		goto unmap_pci_bar;
14258c2ecf20Sopenharmony_ci	}
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	/* Allocate request mem */
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	dprintk("req_size=%d, max_requests=%d\n", req_size, hba->max_requests);
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	hba->req_size = req_size;
14328c2ecf20Sopenharmony_ci	hba->req_list = NULL;
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	for (i = 0; i < hba->max_requests; i++) {
14358c2ecf20Sopenharmony_ci		start_virt = dma_alloc_coherent(&pcidev->dev,
14368c2ecf20Sopenharmony_ci					hba->req_size + 0x20,
14378c2ecf20Sopenharmony_ci					&start_phy, GFP_KERNEL);
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci		if (!start_virt) {
14408c2ecf20Sopenharmony_ci			printk(KERN_ERR "scsi%d: fail to alloc request mem\n",
14418c2ecf20Sopenharmony_ci						hba->host->host_no);
14428c2ecf20Sopenharmony_ci			goto free_request_mem;
14438c2ecf20Sopenharmony_ci		}
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci		hba->dma_coherent[i] = start_virt;
14468c2ecf20Sopenharmony_ci		hba->dma_coherent_handle[i] = start_phy;
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci		if ((start_phy & 0x1f) != 0) {
14498c2ecf20Sopenharmony_ci			offset = ((start_phy + 0x1f) & ~0x1f) - start_phy;
14508c2ecf20Sopenharmony_ci			start_phy += offset;
14518c2ecf20Sopenharmony_ci			start_virt += offset;
14528c2ecf20Sopenharmony_ci		}
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci		hba->reqs[i].next = NULL;
14558c2ecf20Sopenharmony_ci		hba->reqs[i].req_virt = start_virt;
14568c2ecf20Sopenharmony_ci		hba->reqs[i].req_shifted_phy = start_phy >> 5;
14578c2ecf20Sopenharmony_ci		hba->reqs[i].index = i;
14588c2ecf20Sopenharmony_ci		free_req(hba, &hba->reqs[i]);
14598c2ecf20Sopenharmony_ci	}
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	/* Enable Interrupt and start background task */
14628c2ecf20Sopenharmony_ci	if (hptiop_initialize_iop(hba))
14638c2ecf20Sopenharmony_ci		goto free_request_mem;
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	if (scsi_add_host(host, &pcidev->dev)) {
14668c2ecf20Sopenharmony_ci		printk(KERN_ERR "scsi%d: scsi_add_host failed\n",
14678c2ecf20Sopenharmony_ci					hba->host->host_no);
14688c2ecf20Sopenharmony_ci		goto free_request_mem;
14698c2ecf20Sopenharmony_ci	}
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci	scsi_scan_host(host);
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	dprintk("scsi%d: hptiop_probe successfully\n", hba->host->host_no);
14748c2ecf20Sopenharmony_ci	return 0;
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_cifree_request_mem:
14778c2ecf20Sopenharmony_ci	for (i = 0; i < hba->max_requests; i++) {
14788c2ecf20Sopenharmony_ci		if (hba->dma_coherent[i] && hba->dma_coherent_handle[i])
14798c2ecf20Sopenharmony_ci			dma_free_coherent(&hba->pcidev->dev,
14808c2ecf20Sopenharmony_ci					hba->req_size + 0x20,
14818c2ecf20Sopenharmony_ci					hba->dma_coherent[i],
14828c2ecf20Sopenharmony_ci					hba->dma_coherent_handle[i]);
14838c2ecf20Sopenharmony_ci		else
14848c2ecf20Sopenharmony_ci			break;
14858c2ecf20Sopenharmony_ci	}
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	free_irq(hba->pcidev->irq, hba);
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ciunmap_pci_bar:
14908c2ecf20Sopenharmony_ci	hba->ops->internal_memfree(hba);
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	hba->ops->unmap_pci_bar(hba);
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_cifree_scsi_host:
14958c2ecf20Sopenharmony_ci	scsi_host_put(host);
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_cifree_pci_regions:
14988c2ecf20Sopenharmony_ci	pci_release_regions(pcidev);
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_cidisable_pci_device:
15018c2ecf20Sopenharmony_ci	pci_disable_device(pcidev);
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci	dprintk("scsi%d: hptiop_probe fail\n", host ? host->host_no : 0);
15048c2ecf20Sopenharmony_ci	return -ENODEV;
15058c2ecf20Sopenharmony_ci}
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_cistatic void hptiop_shutdown(struct pci_dev *pcidev)
15088c2ecf20Sopenharmony_ci{
15098c2ecf20Sopenharmony_ci	struct Scsi_Host *host = pci_get_drvdata(pcidev);
15108c2ecf20Sopenharmony_ci	struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	dprintk("hptiop_shutdown(%p)\n", hba);
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci	/* stop the iop */
15158c2ecf20Sopenharmony_ci	if (iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_SHUTDOWN, 60000))
15168c2ecf20Sopenharmony_ci		printk(KERN_ERR "scsi%d: shutdown the iop timeout\n",
15178c2ecf20Sopenharmony_ci					hba->host->host_no);
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	/* disable all outbound interrupts */
15208c2ecf20Sopenharmony_ci	hba->ops->disable_intr(hba);
15218c2ecf20Sopenharmony_ci}
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_cistatic void hptiop_disable_intr_itl(struct hptiop_hba *hba)
15248c2ecf20Sopenharmony_ci{
15258c2ecf20Sopenharmony_ci	u32 int_mask;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	int_mask = readl(&hba->u.itl.iop->outbound_intmask);
15288c2ecf20Sopenharmony_ci	writel(int_mask |
15298c2ecf20Sopenharmony_ci		IOPMU_OUTBOUND_INT_MSG0 | IOPMU_OUTBOUND_INT_POSTQUEUE,
15308c2ecf20Sopenharmony_ci		&hba->u.itl.iop->outbound_intmask);
15318c2ecf20Sopenharmony_ci	readl(&hba->u.itl.iop->outbound_intmask);
15328c2ecf20Sopenharmony_ci}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_cistatic void hptiop_disable_intr_mv(struct hptiop_hba *hba)
15358c2ecf20Sopenharmony_ci{
15368c2ecf20Sopenharmony_ci	writel(0, &hba->u.mv.regs->outbound_intmask);
15378c2ecf20Sopenharmony_ci	readl(&hba->u.mv.regs->outbound_intmask);
15388c2ecf20Sopenharmony_ci}
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_cistatic void hptiop_disable_intr_mvfrey(struct hptiop_hba *hba)
15418c2ecf20Sopenharmony_ci{
15428c2ecf20Sopenharmony_ci	writel(0, &(hba->u.mvfrey.mu->f0_doorbell_enable));
15438c2ecf20Sopenharmony_ci	readl(&(hba->u.mvfrey.mu->f0_doorbell_enable));
15448c2ecf20Sopenharmony_ci	writel(0, &(hba->u.mvfrey.mu->isr_enable));
15458c2ecf20Sopenharmony_ci	readl(&(hba->u.mvfrey.mu->isr_enable));
15468c2ecf20Sopenharmony_ci	writel(0, &(hba->u.mvfrey.mu->pcie_f0_int_enable));
15478c2ecf20Sopenharmony_ci	readl(&(hba->u.mvfrey.mu->pcie_f0_int_enable));
15488c2ecf20Sopenharmony_ci}
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_cistatic void hptiop_remove(struct pci_dev *pcidev)
15518c2ecf20Sopenharmony_ci{
15528c2ecf20Sopenharmony_ci	struct Scsi_Host *host = pci_get_drvdata(pcidev);
15538c2ecf20Sopenharmony_ci	struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
15548c2ecf20Sopenharmony_ci	u32 i;
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	dprintk("scsi%d: hptiop_remove\n", hba->host->host_no);
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	scsi_remove_host(host);
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	hptiop_shutdown(pcidev);
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	free_irq(hba->pcidev->irq, hba);
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci	for (i = 0; i < hba->max_requests; i++) {
15658c2ecf20Sopenharmony_ci		if (hba->dma_coherent[i] && hba->dma_coherent_handle[i])
15668c2ecf20Sopenharmony_ci			dma_free_coherent(&hba->pcidev->dev,
15678c2ecf20Sopenharmony_ci					hba->req_size + 0x20,
15688c2ecf20Sopenharmony_ci					hba->dma_coherent[i],
15698c2ecf20Sopenharmony_ci					hba->dma_coherent_handle[i]);
15708c2ecf20Sopenharmony_ci		else
15718c2ecf20Sopenharmony_ci			break;
15728c2ecf20Sopenharmony_ci	}
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	hba->ops->internal_memfree(hba);
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci	hba->ops->unmap_pci_bar(hba);
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	pci_release_regions(hba->pcidev);
15798c2ecf20Sopenharmony_ci	pci_set_drvdata(hba->pcidev, NULL);
15808c2ecf20Sopenharmony_ci	pci_disable_device(hba->pcidev);
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci	scsi_host_put(host);
15838c2ecf20Sopenharmony_ci}
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_cistatic struct hptiop_adapter_ops hptiop_itl_ops = {
15868c2ecf20Sopenharmony_ci	.family            = INTEL_BASED_IOP,
15878c2ecf20Sopenharmony_ci	.iop_wait_ready    = iop_wait_ready_itl,
15888c2ecf20Sopenharmony_ci	.internal_memalloc = hptiop_internal_memalloc_itl,
15898c2ecf20Sopenharmony_ci	.internal_memfree  = hptiop_internal_memfree_itl,
15908c2ecf20Sopenharmony_ci	.map_pci_bar       = hptiop_map_pci_bar_itl,
15918c2ecf20Sopenharmony_ci	.unmap_pci_bar     = hptiop_unmap_pci_bar_itl,
15928c2ecf20Sopenharmony_ci	.enable_intr       = hptiop_enable_intr_itl,
15938c2ecf20Sopenharmony_ci	.disable_intr      = hptiop_disable_intr_itl,
15948c2ecf20Sopenharmony_ci	.get_config        = iop_get_config_itl,
15958c2ecf20Sopenharmony_ci	.set_config        = iop_set_config_itl,
15968c2ecf20Sopenharmony_ci	.iop_intr          = iop_intr_itl,
15978c2ecf20Sopenharmony_ci	.post_msg          = hptiop_post_msg_itl,
15988c2ecf20Sopenharmony_ci	.post_req          = hptiop_post_req_itl,
15998c2ecf20Sopenharmony_ci	.hw_dma_bit_mask   = 64,
16008c2ecf20Sopenharmony_ci	.reset_comm        = hptiop_reset_comm_itl,
16018c2ecf20Sopenharmony_ci	.host_phy_flag     = cpu_to_le64(0),
16028c2ecf20Sopenharmony_ci};
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_cistatic struct hptiop_adapter_ops hptiop_mv_ops = {
16058c2ecf20Sopenharmony_ci	.family            = MV_BASED_IOP,
16068c2ecf20Sopenharmony_ci	.iop_wait_ready    = iop_wait_ready_mv,
16078c2ecf20Sopenharmony_ci	.internal_memalloc = hptiop_internal_memalloc_mv,
16088c2ecf20Sopenharmony_ci	.internal_memfree  = hptiop_internal_memfree_mv,
16098c2ecf20Sopenharmony_ci	.map_pci_bar       = hptiop_map_pci_bar_mv,
16108c2ecf20Sopenharmony_ci	.unmap_pci_bar     = hptiop_unmap_pci_bar_mv,
16118c2ecf20Sopenharmony_ci	.enable_intr       = hptiop_enable_intr_mv,
16128c2ecf20Sopenharmony_ci	.disable_intr      = hptiop_disable_intr_mv,
16138c2ecf20Sopenharmony_ci	.get_config        = iop_get_config_mv,
16148c2ecf20Sopenharmony_ci	.set_config        = iop_set_config_mv,
16158c2ecf20Sopenharmony_ci	.iop_intr          = iop_intr_mv,
16168c2ecf20Sopenharmony_ci	.post_msg          = hptiop_post_msg_mv,
16178c2ecf20Sopenharmony_ci	.post_req          = hptiop_post_req_mv,
16188c2ecf20Sopenharmony_ci	.hw_dma_bit_mask   = 33,
16198c2ecf20Sopenharmony_ci	.reset_comm        = hptiop_reset_comm_mv,
16208c2ecf20Sopenharmony_ci	.host_phy_flag     = cpu_to_le64(0),
16218c2ecf20Sopenharmony_ci};
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_cistatic struct hptiop_adapter_ops hptiop_mvfrey_ops = {
16248c2ecf20Sopenharmony_ci	.family            = MVFREY_BASED_IOP,
16258c2ecf20Sopenharmony_ci	.iop_wait_ready    = iop_wait_ready_mvfrey,
16268c2ecf20Sopenharmony_ci	.internal_memalloc = hptiop_internal_memalloc_mvfrey,
16278c2ecf20Sopenharmony_ci	.internal_memfree  = hptiop_internal_memfree_mvfrey,
16288c2ecf20Sopenharmony_ci	.map_pci_bar       = hptiop_map_pci_bar_mvfrey,
16298c2ecf20Sopenharmony_ci	.unmap_pci_bar     = hptiop_unmap_pci_bar_mvfrey,
16308c2ecf20Sopenharmony_ci	.enable_intr       = hptiop_enable_intr_mvfrey,
16318c2ecf20Sopenharmony_ci	.disable_intr      = hptiop_disable_intr_mvfrey,
16328c2ecf20Sopenharmony_ci	.get_config        = iop_get_config_mvfrey,
16338c2ecf20Sopenharmony_ci	.set_config        = iop_set_config_mvfrey,
16348c2ecf20Sopenharmony_ci	.iop_intr          = iop_intr_mvfrey,
16358c2ecf20Sopenharmony_ci	.post_msg          = hptiop_post_msg_mvfrey,
16368c2ecf20Sopenharmony_ci	.post_req          = hptiop_post_req_mvfrey,
16378c2ecf20Sopenharmony_ci	.hw_dma_bit_mask   = 64,
16388c2ecf20Sopenharmony_ci	.reset_comm        = hptiop_reset_comm_mvfrey,
16398c2ecf20Sopenharmony_ci	.host_phy_flag     = cpu_to_le64(1),
16408c2ecf20Sopenharmony_ci};
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_cistatic struct pci_device_id hptiop_id_table[] = {
16438c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3220), (kernel_ulong_t)&hptiop_itl_ops },
16448c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3320), (kernel_ulong_t)&hptiop_itl_ops },
16458c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3410), (kernel_ulong_t)&hptiop_itl_ops },
16468c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3510), (kernel_ulong_t)&hptiop_itl_ops },
16478c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3511), (kernel_ulong_t)&hptiop_itl_ops },
16488c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3520), (kernel_ulong_t)&hptiop_itl_ops },
16498c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3521), (kernel_ulong_t)&hptiop_itl_ops },
16508c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3522), (kernel_ulong_t)&hptiop_itl_ops },
16518c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3530), (kernel_ulong_t)&hptiop_itl_ops },
16528c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3540), (kernel_ulong_t)&hptiop_itl_ops },
16538c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3560), (kernel_ulong_t)&hptiop_itl_ops },
16548c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x4210), (kernel_ulong_t)&hptiop_itl_ops },
16558c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x4211), (kernel_ulong_t)&hptiop_itl_ops },
16568c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x4310), (kernel_ulong_t)&hptiop_itl_ops },
16578c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x4311), (kernel_ulong_t)&hptiop_itl_ops },
16588c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x4320), (kernel_ulong_t)&hptiop_itl_ops },
16598c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x4321), (kernel_ulong_t)&hptiop_itl_ops },
16608c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x4322), (kernel_ulong_t)&hptiop_itl_ops },
16618c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x4400), (kernel_ulong_t)&hptiop_itl_ops },
16628c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3120), (kernel_ulong_t)&hptiop_mv_ops },
16638c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3122), (kernel_ulong_t)&hptiop_mv_ops },
16648c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3020), (kernel_ulong_t)&hptiop_mv_ops },
16658c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x4520), (kernel_ulong_t)&hptiop_mvfrey_ops },
16668c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x4522), (kernel_ulong_t)&hptiop_mvfrey_ops },
16678c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3610), (kernel_ulong_t)&hptiop_mvfrey_ops },
16688c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3611), (kernel_ulong_t)&hptiop_mvfrey_ops },
16698c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3620), (kernel_ulong_t)&hptiop_mvfrey_ops },
16708c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3622), (kernel_ulong_t)&hptiop_mvfrey_ops },
16718c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3640), (kernel_ulong_t)&hptiop_mvfrey_ops },
16728c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3660), (kernel_ulong_t)&hptiop_mvfrey_ops },
16738c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3680), (kernel_ulong_t)&hptiop_mvfrey_ops },
16748c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(TTI, 0x3690), (kernel_ulong_t)&hptiop_mvfrey_ops },
16758c2ecf20Sopenharmony_ci	{},
16768c2ecf20Sopenharmony_ci};
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hptiop_id_table);
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_cistatic struct pci_driver hptiop_pci_driver = {
16818c2ecf20Sopenharmony_ci	.name       = driver_name,
16828c2ecf20Sopenharmony_ci	.id_table   = hptiop_id_table,
16838c2ecf20Sopenharmony_ci	.probe      = hptiop_probe,
16848c2ecf20Sopenharmony_ci	.remove     = hptiop_remove,
16858c2ecf20Sopenharmony_ci	.shutdown   = hptiop_shutdown,
16868c2ecf20Sopenharmony_ci};
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_cistatic int __init hptiop_module_init(void)
16898c2ecf20Sopenharmony_ci{
16908c2ecf20Sopenharmony_ci	printk(KERN_INFO "%s %s\n", driver_name_long, driver_ver);
16918c2ecf20Sopenharmony_ci	return pci_register_driver(&hptiop_pci_driver);
16928c2ecf20Sopenharmony_ci}
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_cistatic void __exit hptiop_module_exit(void)
16958c2ecf20Sopenharmony_ci{
16968c2ecf20Sopenharmony_ci	pci_unregister_driver(&hptiop_pci_driver);
16978c2ecf20Sopenharmony_ci}
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_cimodule_init(hptiop_module_init);
17018c2ecf20Sopenharmony_cimodule_exit(hptiop_module_exit);
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
17048c2ecf20Sopenharmony_ci
1705