xref: /openbmc/linux/drivers/scsi/hptiop.c (revision 9bcf0910)
1ede1e6f8SHighPoint Linux Team /*
200f59701SHighPoint Linux Team  * HighPoint RR3xxx/4xxx controller driver for Linux
3db9b6e89SHighPoint Linux Team  * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
4ede1e6f8SHighPoint Linux Team  *
5ede1e6f8SHighPoint Linux Team  * This program is free software; you can redistribute it and/or modify
6ede1e6f8SHighPoint Linux Team  * it under the terms of the GNU General Public License as published by
7ede1e6f8SHighPoint Linux Team  * the Free Software Foundation; version 2 of the License.
8ede1e6f8SHighPoint Linux Team  *
9ede1e6f8SHighPoint Linux Team  * This program is distributed in the hope that it will be useful,
10ede1e6f8SHighPoint Linux Team  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11ede1e6f8SHighPoint Linux Team  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12ede1e6f8SHighPoint Linux Team  * GNU General Public License for more details.
13ede1e6f8SHighPoint Linux Team  *
14ede1e6f8SHighPoint Linux Team  * Please report bugs/comments/suggestions to linux@highpoint-tech.com
15ede1e6f8SHighPoint Linux Team  *
16ede1e6f8SHighPoint Linux Team  * For more information, visit http://www.highpoint-tech.com
17ede1e6f8SHighPoint Linux Team  */
18ede1e6f8SHighPoint Linux Team #include <linux/module.h>
19ede1e6f8SHighPoint Linux Team #include <linux/types.h>
20ede1e6f8SHighPoint Linux Team #include <linux/string.h>
21ede1e6f8SHighPoint Linux Team #include <linux/kernel.h>
22ede1e6f8SHighPoint Linux Team #include <linux/pci.h>
23ede1e6f8SHighPoint Linux Team #include <linux/interrupt.h>
24ede1e6f8SHighPoint Linux Team #include <linux/errno.h>
25ede1e6f8SHighPoint Linux Team #include <linux/delay.h>
26ede1e6f8SHighPoint Linux Team #include <linux/timer.h>
27ede1e6f8SHighPoint Linux Team #include <linux/spinlock.h>
28ede1e6f8SHighPoint Linux Team #include <linux/hdreg.h>
29ede1e6f8SHighPoint Linux Team #include <asm/uaccess.h>
30ede1e6f8SHighPoint Linux Team #include <asm/io.h>
31ede1e6f8SHighPoint Linux Team #include <asm/div64.h>
32ede1e6f8SHighPoint Linux Team #include <scsi/scsi_cmnd.h>
33ede1e6f8SHighPoint Linux Team #include <scsi/scsi_device.h>
34ede1e6f8SHighPoint Linux Team #include <scsi/scsi.h>
35ede1e6f8SHighPoint Linux Team #include <scsi/scsi_tcq.h>
36ede1e6f8SHighPoint Linux Team #include <scsi/scsi_host.h>
37ede1e6f8SHighPoint Linux Team 
38ede1e6f8SHighPoint Linux Team #include "hptiop.h"
39ede1e6f8SHighPoint Linux Team 
40ede1e6f8SHighPoint Linux Team MODULE_AUTHOR("HighPoint Technologies, Inc.");
4100f59701SHighPoint Linux Team MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx/4xxx Controller Driver");
42ede1e6f8SHighPoint Linux Team 
43ede1e6f8SHighPoint Linux Team static char driver_name[] = "hptiop";
4400f59701SHighPoint Linux Team static const char driver_name_long[] = "RocketRAID 3xxx/4xxx Controller driver";
4500f59701SHighPoint Linux Team static const char driver_ver[] = "v1.3 (071203)";
46ede1e6f8SHighPoint Linux Team 
4700f59701SHighPoint Linux Team static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec);
4800f59701SHighPoint Linux Team static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
4900f59701SHighPoint Linux Team 				struct hpt_iop_request_scsi_command *req);
5000f59701SHighPoint Linux Team static void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 tag);
5100f59701SHighPoint Linux Team static void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag);
52ede1e6f8SHighPoint Linux Team static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg);
53ede1e6f8SHighPoint Linux Team 
5400f59701SHighPoint Linux Team static int iop_wait_ready_itl(struct hptiop_hba *hba, u32 millisec)
55ede1e6f8SHighPoint Linux Team {
56ede1e6f8SHighPoint Linux Team 	u32 req = 0;
57ede1e6f8SHighPoint Linux Team 	int i;
58ede1e6f8SHighPoint Linux Team 
59ede1e6f8SHighPoint Linux Team 	for (i = 0; i < millisec; i++) {
6000f59701SHighPoint Linux Team 		req = readl(&hba->u.itl.iop->inbound_queue);
61ede1e6f8SHighPoint Linux Team 		if (req != IOPMU_QUEUE_EMPTY)
62ede1e6f8SHighPoint Linux Team 			break;
63ede1e6f8SHighPoint Linux Team 		msleep(1);
64ede1e6f8SHighPoint Linux Team 	}
65ede1e6f8SHighPoint Linux Team 
66ede1e6f8SHighPoint Linux Team 	if (req != IOPMU_QUEUE_EMPTY) {
6700f59701SHighPoint Linux Team 		writel(req, &hba->u.itl.iop->outbound_queue);
6800f59701SHighPoint Linux Team 		readl(&hba->u.itl.iop->outbound_intstatus);
69ede1e6f8SHighPoint Linux Team 		return 0;
70ede1e6f8SHighPoint Linux Team 	}
71ede1e6f8SHighPoint Linux Team 
72ede1e6f8SHighPoint Linux Team 	return -1;
73ede1e6f8SHighPoint Linux Team }
74ede1e6f8SHighPoint Linux Team 
7500f59701SHighPoint Linux Team static int iop_wait_ready_mv(struct hptiop_hba *hba, u32 millisec)
76ede1e6f8SHighPoint Linux Team {
7700f59701SHighPoint Linux Team 	return iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_NOP, millisec);
78ede1e6f8SHighPoint Linux Team }
79ede1e6f8SHighPoint Linux Team 
8000f59701SHighPoint Linux Team static void hptiop_request_callback_itl(struct hptiop_hba *hba, u32 tag)
8100f59701SHighPoint Linux Team {
8200f59701SHighPoint Linux Team 	if (tag & IOPMU_QUEUE_ADDR_HOST_BIT)
8300f59701SHighPoint Linux Team 		hptiop_host_request_callback_itl(hba,
8400f59701SHighPoint Linux Team 				tag & ~IOPMU_QUEUE_ADDR_HOST_BIT);
8500f59701SHighPoint Linux Team 	else
8600f59701SHighPoint Linux Team 		hptiop_iop_request_callback_itl(hba, tag);
8700f59701SHighPoint Linux Team }
8800f59701SHighPoint Linux Team 
8900f59701SHighPoint Linux Team static void hptiop_drain_outbound_queue_itl(struct hptiop_hba *hba)
90ede1e6f8SHighPoint Linux Team {
91ede1e6f8SHighPoint Linux Team 	u32 req;
92ede1e6f8SHighPoint Linux Team 
9300f59701SHighPoint Linux Team 	while ((req = readl(&hba->u.itl.iop->outbound_queue)) !=
9400f59701SHighPoint Linux Team 						IOPMU_QUEUE_EMPTY) {
95ede1e6f8SHighPoint Linux Team 
96ede1e6f8SHighPoint Linux Team 		if (req & IOPMU_QUEUE_MASK_HOST_BITS)
9700f59701SHighPoint Linux Team 			hptiop_request_callback_itl(hba, req);
98ede1e6f8SHighPoint Linux Team 		else {
99ede1e6f8SHighPoint Linux Team 			struct hpt_iop_request_header __iomem * p;
100ede1e6f8SHighPoint Linux Team 
101ede1e6f8SHighPoint Linux Team 			p = (struct hpt_iop_request_header __iomem *)
10200f59701SHighPoint Linux Team 				((char __iomem *)hba->u.itl.iop + req);
103ede1e6f8SHighPoint Linux Team 
104ede1e6f8SHighPoint Linux Team 			if (readl(&p->flags) & IOP_REQUEST_FLAG_SYNC_REQUEST) {
105ede1e6f8SHighPoint Linux Team 				if (readl(&p->context))
10600f59701SHighPoint Linux Team 					hptiop_request_callback_itl(hba, req);
107ede1e6f8SHighPoint Linux Team 				else
108ede1e6f8SHighPoint Linux Team 					writel(1, &p->context);
109ede1e6f8SHighPoint Linux Team 			}
110ede1e6f8SHighPoint Linux Team 			else
11100f59701SHighPoint Linux Team 				hptiop_request_callback_itl(hba, req);
112ede1e6f8SHighPoint Linux Team 		}
113ede1e6f8SHighPoint Linux Team 	}
114ede1e6f8SHighPoint Linux Team }
115ede1e6f8SHighPoint Linux Team 
11600f59701SHighPoint Linux Team static int iop_intr_itl(struct hptiop_hba *hba)
117ede1e6f8SHighPoint Linux Team {
11800f59701SHighPoint Linux Team 	struct hpt_iopmu_itl __iomem *iop = hba->u.itl.iop;
119ede1e6f8SHighPoint Linux Team 	u32 status;
120ede1e6f8SHighPoint Linux Team 	int ret = 0;
121ede1e6f8SHighPoint Linux Team 
122ede1e6f8SHighPoint Linux Team 	status = readl(&iop->outbound_intstatus);
123ede1e6f8SHighPoint Linux Team 
124ede1e6f8SHighPoint Linux Team 	if (status & IOPMU_OUTBOUND_INT_MSG0) {
125ede1e6f8SHighPoint Linux Team 		u32 msg = readl(&iop->outbound_msgaddr0);
12600f59701SHighPoint Linux Team 
127ede1e6f8SHighPoint Linux Team 		dprintk("received outbound msg %x\n", msg);
128ede1e6f8SHighPoint Linux Team 		writel(IOPMU_OUTBOUND_INT_MSG0, &iop->outbound_intstatus);
129ede1e6f8SHighPoint Linux Team 		hptiop_message_callback(hba, msg);
130ede1e6f8SHighPoint Linux Team 		ret = 1;
131ede1e6f8SHighPoint Linux Team 	}
132ede1e6f8SHighPoint Linux Team 
133ede1e6f8SHighPoint Linux Team 	if (status & IOPMU_OUTBOUND_INT_POSTQUEUE) {
13400f59701SHighPoint Linux Team 		hptiop_drain_outbound_queue_itl(hba);
135ede1e6f8SHighPoint Linux Team 		ret = 1;
136ede1e6f8SHighPoint Linux Team 	}
137ede1e6f8SHighPoint Linux Team 
138ede1e6f8SHighPoint Linux Team 	return ret;
139ede1e6f8SHighPoint Linux Team }
140ede1e6f8SHighPoint Linux Team 
14100f59701SHighPoint Linux Team static u64 mv_outbound_read(struct hpt_iopmu_mv __iomem *mu)
14200f59701SHighPoint Linux Team {
14300f59701SHighPoint Linux Team 	u32 outbound_tail = readl(&mu->outbound_tail);
14400f59701SHighPoint Linux Team 	u32 outbound_head = readl(&mu->outbound_head);
14500f59701SHighPoint Linux Team 
14600f59701SHighPoint Linux Team 	if (outbound_tail != outbound_head) {
14700f59701SHighPoint Linux Team 		u64 p;
14800f59701SHighPoint Linux Team 
14900f59701SHighPoint Linux Team 		memcpy_fromio(&p, &mu->outbound_q[mu->outbound_tail], 8);
15000f59701SHighPoint Linux Team 		outbound_tail++;
15100f59701SHighPoint Linux Team 
15200f59701SHighPoint Linux Team 		if (outbound_tail == MVIOP_QUEUE_LEN)
15300f59701SHighPoint Linux Team 			outbound_tail = 0;
15400f59701SHighPoint Linux Team 		writel(outbound_tail, &mu->outbound_tail);
15500f59701SHighPoint Linux Team 		return p;
15600f59701SHighPoint Linux Team 	} else
15700f59701SHighPoint Linux Team 		return 0;
15800f59701SHighPoint Linux Team }
15900f59701SHighPoint Linux Team 
16000f59701SHighPoint Linux Team static void mv_inbound_write(u64 p, struct hptiop_hba *hba)
16100f59701SHighPoint Linux Team {
16200f59701SHighPoint Linux Team 	u32 inbound_head = readl(&hba->u.mv.mu->inbound_head);
16300f59701SHighPoint Linux Team 	u32 head = inbound_head + 1;
16400f59701SHighPoint Linux Team 
16500f59701SHighPoint Linux Team 	if (head == MVIOP_QUEUE_LEN)
16600f59701SHighPoint Linux Team 		head = 0;
16700f59701SHighPoint Linux Team 
16800f59701SHighPoint Linux Team 	memcpy_toio(&hba->u.mv.mu->inbound_q[inbound_head], &p, 8);
16900f59701SHighPoint Linux Team 	writel(head, &hba->u.mv.mu->inbound_head);
17000f59701SHighPoint Linux Team 	writel(MVIOP_MU_INBOUND_INT_POSTQUEUE,
17100f59701SHighPoint Linux Team 			&hba->u.mv.regs->inbound_doorbell);
17200f59701SHighPoint Linux Team }
17300f59701SHighPoint Linux Team 
17400f59701SHighPoint Linux Team static void hptiop_request_callback_mv(struct hptiop_hba *hba, u64 tag)
17500f59701SHighPoint Linux Team {
17600f59701SHighPoint Linux Team 	u32 req_type = (tag >> 5) & 0x7;
17700f59701SHighPoint Linux Team 	struct hpt_iop_request_scsi_command *req;
17800f59701SHighPoint Linux Team 
17900f59701SHighPoint Linux Team 	dprintk("hptiop_request_callback_mv: tag=%llx\n", tag);
18000f59701SHighPoint Linux Team 
18100f59701SHighPoint Linux Team 	BUG_ON((tag & MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT) == 0);
18200f59701SHighPoint Linux Team 
18300f59701SHighPoint Linux Team 	switch (req_type) {
18400f59701SHighPoint Linux Team 	case IOP_REQUEST_TYPE_GET_CONFIG:
18500f59701SHighPoint Linux Team 	case IOP_REQUEST_TYPE_SET_CONFIG:
18600f59701SHighPoint Linux Team 		hba->msg_done = 1;
18700f59701SHighPoint Linux Team 		break;
18800f59701SHighPoint Linux Team 
18900f59701SHighPoint Linux Team 	case IOP_REQUEST_TYPE_SCSI_COMMAND:
19000f59701SHighPoint Linux Team 		req = hba->reqs[tag >> 8].req_virt;
19100f59701SHighPoint Linux Team 		if (likely(tag & MVIOP_MU_QUEUE_REQUEST_RESULT_BIT))
19200f59701SHighPoint Linux Team 			req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS);
19300f59701SHighPoint Linux Team 
19400f59701SHighPoint Linux Team 		hptiop_finish_scsi_req(hba, tag>>8, req);
19500f59701SHighPoint Linux Team 		break;
19600f59701SHighPoint Linux Team 
19700f59701SHighPoint Linux Team 	default:
19800f59701SHighPoint Linux Team 		break;
19900f59701SHighPoint Linux Team 	}
20000f59701SHighPoint Linux Team }
20100f59701SHighPoint Linux Team 
20200f59701SHighPoint Linux Team static int iop_intr_mv(struct hptiop_hba *hba)
20300f59701SHighPoint Linux Team {
20400f59701SHighPoint Linux Team 	u32 status;
20500f59701SHighPoint Linux Team 	int ret = 0;
20600f59701SHighPoint Linux Team 
20700f59701SHighPoint Linux Team 	status = readl(&hba->u.mv.regs->outbound_doorbell);
20800f59701SHighPoint Linux Team 	writel(~status, &hba->u.mv.regs->outbound_doorbell);
20900f59701SHighPoint Linux Team 
21000f59701SHighPoint Linux Team 	if (status & MVIOP_MU_OUTBOUND_INT_MSG) {
21100f59701SHighPoint Linux Team 		u32 msg;
21200f59701SHighPoint Linux Team 		msg = readl(&hba->u.mv.mu->outbound_msg);
21300f59701SHighPoint Linux Team 		dprintk("received outbound msg %x\n", msg);
21400f59701SHighPoint Linux Team 		hptiop_message_callback(hba, msg);
21500f59701SHighPoint Linux Team 		ret = 1;
21600f59701SHighPoint Linux Team 	}
21700f59701SHighPoint Linux Team 
21800f59701SHighPoint Linux Team 	if (status & MVIOP_MU_OUTBOUND_INT_POSTQUEUE) {
21900f59701SHighPoint Linux Team 		u64 tag;
22000f59701SHighPoint Linux Team 
22100f59701SHighPoint Linux Team 		while ((tag = mv_outbound_read(hba->u.mv.mu)))
22200f59701SHighPoint Linux Team 			hptiop_request_callback_mv(hba, tag);
22300f59701SHighPoint Linux Team 		ret = 1;
22400f59701SHighPoint Linux Team 	}
22500f59701SHighPoint Linux Team 
22600f59701SHighPoint Linux Team 	return ret;
22700f59701SHighPoint Linux Team }
22800f59701SHighPoint Linux Team 
22900f59701SHighPoint Linux Team static int iop_send_sync_request_itl(struct hptiop_hba *hba,
230ede1e6f8SHighPoint Linux Team 					void __iomem *_req, u32 millisec)
231ede1e6f8SHighPoint Linux Team {
232ede1e6f8SHighPoint Linux Team 	struct hpt_iop_request_header __iomem *req = _req;
233ede1e6f8SHighPoint Linux Team 	u32 i;
234ede1e6f8SHighPoint Linux Team 
23500f59701SHighPoint Linux Team 	writel(readl(&req->flags) | IOP_REQUEST_FLAG_SYNC_REQUEST, &req->flags);
236ede1e6f8SHighPoint Linux Team 	writel(0, &req->context);
23700f59701SHighPoint Linux Team 	writel((unsigned long)req - (unsigned long)hba->u.itl.iop,
23800f59701SHighPoint Linux Team 			&hba->u.itl.iop->inbound_queue);
23900f59701SHighPoint Linux Team 	readl(&hba->u.itl.iop->outbound_intstatus);
240ede1e6f8SHighPoint Linux Team 
241ede1e6f8SHighPoint Linux Team 	for (i = 0; i < millisec; i++) {
24200f59701SHighPoint Linux Team 		iop_intr_itl(hba);
243ede1e6f8SHighPoint Linux Team 		if (readl(&req->context))
244ede1e6f8SHighPoint Linux Team 			return 0;
245ede1e6f8SHighPoint Linux Team 		msleep(1);
246ede1e6f8SHighPoint Linux Team 	}
247ede1e6f8SHighPoint Linux Team 
248ede1e6f8SHighPoint Linux Team 	return -1;
249ede1e6f8SHighPoint Linux Team }
250ede1e6f8SHighPoint Linux Team 
25100f59701SHighPoint Linux Team static int iop_send_sync_request_mv(struct hptiop_hba *hba,
25200f59701SHighPoint Linux Team 					u32 size_bits, u32 millisec)
25300f59701SHighPoint Linux Team {
25400f59701SHighPoint Linux Team 	struct hpt_iop_request_header *reqhdr = hba->u.mv.internal_req;
25500f59701SHighPoint Linux Team 	u32 i;
25600f59701SHighPoint Linux Team 
25700f59701SHighPoint Linux Team 	hba->msg_done = 0;
25800f59701SHighPoint Linux Team 	reqhdr->flags |= cpu_to_le32(IOP_REQUEST_FLAG_SYNC_REQUEST);
25900f59701SHighPoint Linux Team 	mv_inbound_write(hba->u.mv.internal_req_phy |
26000f59701SHighPoint Linux Team 			MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bits, hba);
26100f59701SHighPoint Linux Team 
26200f59701SHighPoint Linux Team 	for (i = 0; i < millisec; i++) {
26300f59701SHighPoint Linux Team 		iop_intr_mv(hba);
26400f59701SHighPoint Linux Team 		if (hba->msg_done)
26500f59701SHighPoint Linux Team 			return 0;
26600f59701SHighPoint Linux Team 		msleep(1);
26700f59701SHighPoint Linux Team 	}
26800f59701SHighPoint Linux Team 	return -1;
26900f59701SHighPoint Linux Team }
27000f59701SHighPoint Linux Team 
27100f59701SHighPoint Linux Team static void hptiop_post_msg_itl(struct hptiop_hba *hba, u32 msg)
27200f59701SHighPoint Linux Team {
27300f59701SHighPoint Linux Team 	writel(msg, &hba->u.itl.iop->inbound_msgaddr0);
27400f59701SHighPoint Linux Team 	readl(&hba->u.itl.iop->outbound_intstatus);
27500f59701SHighPoint Linux Team }
27600f59701SHighPoint Linux Team 
27700f59701SHighPoint Linux Team static void hptiop_post_msg_mv(struct hptiop_hba *hba, u32 msg)
27800f59701SHighPoint Linux Team {
27900f59701SHighPoint Linux Team 	writel(msg, &hba->u.mv.mu->inbound_msg);
28000f59701SHighPoint Linux Team 	writel(MVIOP_MU_INBOUND_INT_MSG, &hba->u.mv.regs->inbound_doorbell);
28100f59701SHighPoint Linux Team 	readl(&hba->u.mv.regs->inbound_doorbell);
28200f59701SHighPoint Linux Team }
28300f59701SHighPoint Linux Team 
284ede1e6f8SHighPoint Linux Team static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec)
285ede1e6f8SHighPoint Linux Team {
286ede1e6f8SHighPoint Linux Team 	u32 i;
287ede1e6f8SHighPoint Linux Team 
288ede1e6f8SHighPoint Linux Team 	hba->msg_done = 0;
28900f59701SHighPoint Linux Team 	hba->ops->post_msg(hba, msg);
290ede1e6f8SHighPoint Linux Team 
291ede1e6f8SHighPoint Linux Team 	for (i = 0; i < millisec; i++) {
292ede1e6f8SHighPoint Linux Team 		spin_lock_irq(hba->host->host_lock);
29300f59701SHighPoint Linux Team 		hba->ops->iop_intr(hba);
294ede1e6f8SHighPoint Linux Team 		spin_unlock_irq(hba->host->host_lock);
295ede1e6f8SHighPoint Linux Team 		if (hba->msg_done)
296ede1e6f8SHighPoint Linux Team 			break;
297ede1e6f8SHighPoint Linux Team 		msleep(1);
298ede1e6f8SHighPoint Linux Team 	}
299ede1e6f8SHighPoint Linux Team 
300ede1e6f8SHighPoint Linux Team 	return hba->msg_done? 0 : -1;
301ede1e6f8SHighPoint Linux Team }
302ede1e6f8SHighPoint Linux Team 
30300f59701SHighPoint Linux Team static int iop_get_config_itl(struct hptiop_hba *hba,
304ede1e6f8SHighPoint Linux Team 				struct hpt_iop_request_get_config *config)
305ede1e6f8SHighPoint Linux Team {
306ede1e6f8SHighPoint Linux Team 	u32 req32;
307ede1e6f8SHighPoint Linux Team 	struct hpt_iop_request_get_config __iomem *req;
308ede1e6f8SHighPoint Linux Team 
30900f59701SHighPoint Linux Team 	req32 = readl(&hba->u.itl.iop->inbound_queue);
310ede1e6f8SHighPoint Linux Team 	if (req32 == IOPMU_QUEUE_EMPTY)
311ede1e6f8SHighPoint Linux Team 		return -1;
312ede1e6f8SHighPoint Linux Team 
313ede1e6f8SHighPoint Linux Team 	req = (struct hpt_iop_request_get_config __iomem *)
31400f59701SHighPoint Linux Team 			((unsigned long)hba->u.itl.iop + req32);
315ede1e6f8SHighPoint Linux Team 
316ede1e6f8SHighPoint Linux Team 	writel(0, &req->header.flags);
317ede1e6f8SHighPoint Linux Team 	writel(IOP_REQUEST_TYPE_GET_CONFIG, &req->header.type);
318ede1e6f8SHighPoint Linux Team 	writel(sizeof(struct hpt_iop_request_get_config), &req->header.size);
319ede1e6f8SHighPoint Linux Team 	writel(IOP_RESULT_PENDING, &req->header.result);
320ede1e6f8SHighPoint Linux Team 
32100f59701SHighPoint Linux Team 	if (iop_send_sync_request_itl(hba, req, 20000)) {
322ede1e6f8SHighPoint Linux Team 		dprintk("Get config send cmd failed\n");
323ede1e6f8SHighPoint Linux Team 		return -1;
324ede1e6f8SHighPoint Linux Team 	}
325ede1e6f8SHighPoint Linux Team 
326ede1e6f8SHighPoint Linux Team 	memcpy_fromio(config, req, sizeof(*config));
32700f59701SHighPoint Linux Team 	writel(req32, &hba->u.itl.iop->outbound_queue);
328ede1e6f8SHighPoint Linux Team 	return 0;
329ede1e6f8SHighPoint Linux Team }
330ede1e6f8SHighPoint Linux Team 
33100f59701SHighPoint Linux Team static int iop_get_config_mv(struct hptiop_hba *hba,
33200f59701SHighPoint Linux Team 				struct hpt_iop_request_get_config *config)
33300f59701SHighPoint Linux Team {
33400f59701SHighPoint Linux Team 	struct hpt_iop_request_get_config *req = hba->u.mv.internal_req;
33500f59701SHighPoint Linux Team 
33600f59701SHighPoint Linux Team 	req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
33700f59701SHighPoint Linux Team 	req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_GET_CONFIG);
33800f59701SHighPoint Linux Team 	req->header.size =
33900f59701SHighPoint Linux Team 		cpu_to_le32(sizeof(struct hpt_iop_request_get_config));
34000f59701SHighPoint Linux Team 	req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
341f6b196a2SJames Bottomley 	req->header.context = cpu_to_le32(IOP_REQUEST_TYPE_GET_CONFIG<<5);
342f6b196a2SJames Bottomley 	req->header.context_hi32 = 0;
34300f59701SHighPoint Linux Team 
34400f59701SHighPoint Linux Team 	if (iop_send_sync_request_mv(hba, 0, 20000)) {
34500f59701SHighPoint Linux Team 		dprintk("Get config send cmd failed\n");
34600f59701SHighPoint Linux Team 		return -1;
34700f59701SHighPoint Linux Team 	}
34800f59701SHighPoint Linux Team 
34900f59701SHighPoint Linux Team 	memcpy(config, req, sizeof(struct hpt_iop_request_get_config));
35000f59701SHighPoint Linux Team 	return 0;
35100f59701SHighPoint Linux Team }
35200f59701SHighPoint Linux Team 
35300f59701SHighPoint Linux Team static int iop_set_config_itl(struct hptiop_hba *hba,
354ede1e6f8SHighPoint Linux Team 				struct hpt_iop_request_set_config *config)
355ede1e6f8SHighPoint Linux Team {
356ede1e6f8SHighPoint Linux Team 	u32 req32;
357ede1e6f8SHighPoint Linux Team 	struct hpt_iop_request_set_config __iomem *req;
358ede1e6f8SHighPoint Linux Team 
35900f59701SHighPoint Linux Team 	req32 = readl(&hba->u.itl.iop->inbound_queue);
360ede1e6f8SHighPoint Linux Team 	if (req32 == IOPMU_QUEUE_EMPTY)
361ede1e6f8SHighPoint Linux Team 		return -1;
362ede1e6f8SHighPoint Linux Team 
363ede1e6f8SHighPoint Linux Team 	req = (struct hpt_iop_request_set_config __iomem *)
36400f59701SHighPoint Linux Team 			((unsigned long)hba->u.itl.iop + req32);
365ede1e6f8SHighPoint Linux Team 
366ede1e6f8SHighPoint Linux Team 	memcpy_toio((u8 __iomem *)req + sizeof(struct hpt_iop_request_header),
367ede1e6f8SHighPoint Linux Team 		(u8 *)config + sizeof(struct hpt_iop_request_header),
368ede1e6f8SHighPoint Linux Team 		sizeof(struct hpt_iop_request_set_config) -
369ede1e6f8SHighPoint Linux Team 			sizeof(struct hpt_iop_request_header));
370ede1e6f8SHighPoint Linux Team 
371ede1e6f8SHighPoint Linux Team 	writel(0, &req->header.flags);
372ede1e6f8SHighPoint Linux Team 	writel(IOP_REQUEST_TYPE_SET_CONFIG, &req->header.type);
373ede1e6f8SHighPoint Linux Team 	writel(sizeof(struct hpt_iop_request_set_config), &req->header.size);
374ede1e6f8SHighPoint Linux Team 	writel(IOP_RESULT_PENDING, &req->header.result);
375ede1e6f8SHighPoint Linux Team 
37600f59701SHighPoint Linux Team 	if (iop_send_sync_request_itl(hba, req, 20000)) {
377ede1e6f8SHighPoint Linux Team 		dprintk("Set config send cmd failed\n");
378ede1e6f8SHighPoint Linux Team 		return -1;
379ede1e6f8SHighPoint Linux Team 	}
380ede1e6f8SHighPoint Linux Team 
38100f59701SHighPoint Linux Team 	writel(req32, &hba->u.itl.iop->outbound_queue);
382ede1e6f8SHighPoint Linux Team 	return 0;
383ede1e6f8SHighPoint Linux Team }
384ede1e6f8SHighPoint Linux Team 
38500f59701SHighPoint Linux Team static int iop_set_config_mv(struct hptiop_hba *hba,
38600f59701SHighPoint Linux Team 				struct hpt_iop_request_set_config *config)
38700f59701SHighPoint Linux Team {
38800f59701SHighPoint Linux Team 	struct hpt_iop_request_set_config *req = hba->u.mv.internal_req;
38900f59701SHighPoint Linux Team 
39000f59701SHighPoint Linux Team 	memcpy(req, config, sizeof(struct hpt_iop_request_set_config));
39100f59701SHighPoint Linux Team 	req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
39200f59701SHighPoint Linux Team 	req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG);
39300f59701SHighPoint Linux Team 	req->header.size =
39400f59701SHighPoint Linux Team 		cpu_to_le32(sizeof(struct hpt_iop_request_set_config));
39500f59701SHighPoint Linux Team 	req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
396f6b196a2SJames Bottomley 	req->header.context = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG<<5);
397f6b196a2SJames Bottomley 	req->header.context_hi32 = 0;
39800f59701SHighPoint Linux Team 
39900f59701SHighPoint Linux Team 	if (iop_send_sync_request_mv(hba, 0, 20000)) {
40000f59701SHighPoint Linux Team 		dprintk("Set config send cmd failed\n");
40100f59701SHighPoint Linux Team 		return -1;
40200f59701SHighPoint Linux Team 	}
40300f59701SHighPoint Linux Team 
40400f59701SHighPoint Linux Team 	return 0;
40500f59701SHighPoint Linux Team }
40600f59701SHighPoint Linux Team 
40700f59701SHighPoint Linux Team static void hptiop_enable_intr_itl(struct hptiop_hba *hba)
40800f59701SHighPoint Linux Team {
40900f59701SHighPoint Linux Team 	writel(~(IOPMU_OUTBOUND_INT_POSTQUEUE | IOPMU_OUTBOUND_INT_MSG0),
41000f59701SHighPoint Linux Team 		&hba->u.itl.iop->outbound_intmask);
41100f59701SHighPoint Linux Team }
41200f59701SHighPoint Linux Team 
41300f59701SHighPoint Linux Team static void hptiop_enable_intr_mv(struct hptiop_hba *hba)
41400f59701SHighPoint Linux Team {
41500f59701SHighPoint Linux Team 	writel(MVIOP_MU_OUTBOUND_INT_POSTQUEUE | MVIOP_MU_OUTBOUND_INT_MSG,
41600f59701SHighPoint Linux Team 		&hba->u.mv.regs->outbound_intmask);
41700f59701SHighPoint Linux Team }
41800f59701SHighPoint Linux Team 
419ede1e6f8SHighPoint Linux Team static int hptiop_initialize_iop(struct hptiop_hba *hba)
420ede1e6f8SHighPoint Linux Team {
421ede1e6f8SHighPoint Linux Team 	/* enable interrupts */
42200f59701SHighPoint Linux Team 	hba->ops->enable_intr(hba);
423ede1e6f8SHighPoint Linux Team 
424ede1e6f8SHighPoint Linux Team 	hba->initialized = 1;
425ede1e6f8SHighPoint Linux Team 
426ede1e6f8SHighPoint Linux Team 	/* start background tasks */
427ede1e6f8SHighPoint Linux Team 	if (iop_send_sync_msg(hba,
428ede1e6f8SHighPoint Linux Team 			IOPMU_INBOUND_MSG0_START_BACKGROUND_TASK, 5000)) {
429ede1e6f8SHighPoint Linux Team 		printk(KERN_ERR "scsi%d: fail to start background task\n",
430ede1e6f8SHighPoint Linux Team 			hba->host->host_no);
431ede1e6f8SHighPoint Linux Team 		return -1;
432ede1e6f8SHighPoint Linux Team 	}
433ede1e6f8SHighPoint Linux Team 	return 0;
434ede1e6f8SHighPoint Linux Team }
435ede1e6f8SHighPoint Linux Team 
43600f59701SHighPoint Linux Team static void __iomem *hptiop_map_pci_bar(struct hptiop_hba *hba, int index)
437ede1e6f8SHighPoint Linux Team {
438ede1e6f8SHighPoint Linux Team 	u32 mem_base_phy, length;
439ede1e6f8SHighPoint Linux Team 	void __iomem *mem_base_virt;
44000f59701SHighPoint Linux Team 
441ede1e6f8SHighPoint Linux Team 	struct pci_dev *pcidev = hba->pcidev;
442ede1e6f8SHighPoint Linux Team 
44300f59701SHighPoint Linux Team 
44400f59701SHighPoint Linux Team 	if (!(pci_resource_flags(pcidev, index) & IORESOURCE_MEM)) {
445ede1e6f8SHighPoint Linux Team 		printk(KERN_ERR "scsi%d: pci resource invalid\n",
446ede1e6f8SHighPoint Linux Team 				hba->host->host_no);
4479bcf0910SHarvey Harrison 		return NULL;
448ede1e6f8SHighPoint Linux Team 	}
449ede1e6f8SHighPoint Linux Team 
45000f59701SHighPoint Linux Team 	mem_base_phy = pci_resource_start(pcidev, index);
45100f59701SHighPoint Linux Team 	length = pci_resource_len(pcidev, index);
452ede1e6f8SHighPoint Linux Team 	mem_base_virt = ioremap(mem_base_phy, length);
453ede1e6f8SHighPoint Linux Team 
454ede1e6f8SHighPoint Linux Team 	if (!mem_base_virt) {
455ede1e6f8SHighPoint Linux Team 		printk(KERN_ERR "scsi%d: Fail to ioremap memory space\n",
456ede1e6f8SHighPoint Linux Team 				hba->host->host_no);
4579bcf0910SHarvey Harrison 		return NULL;
45800f59701SHighPoint Linux Team 	}
45900f59701SHighPoint Linux Team 	return mem_base_virt;
46000f59701SHighPoint Linux Team }
46100f59701SHighPoint Linux Team 
46200f59701SHighPoint Linux Team static int hptiop_map_pci_bar_itl(struct hptiop_hba *hba)
46300f59701SHighPoint Linux Team {
46400f59701SHighPoint Linux Team 	hba->u.itl.iop = hptiop_map_pci_bar(hba, 0);
46500f59701SHighPoint Linux Team 	if (hba->u.itl.iop)
46600f59701SHighPoint Linux Team 		return 0;
46700f59701SHighPoint Linux Team 	else
468ede1e6f8SHighPoint Linux Team 		return -1;
469ede1e6f8SHighPoint Linux Team }
470ede1e6f8SHighPoint Linux Team 
47100f59701SHighPoint Linux Team static void hptiop_unmap_pci_bar_itl(struct hptiop_hba *hba)
47200f59701SHighPoint Linux Team {
47300f59701SHighPoint Linux Team 	iounmap(hba->u.itl.iop);
47400f59701SHighPoint Linux Team }
47500f59701SHighPoint Linux Team 
47600f59701SHighPoint Linux Team static int hptiop_map_pci_bar_mv(struct hptiop_hba *hba)
47700f59701SHighPoint Linux Team {
47800f59701SHighPoint Linux Team 	hba->u.mv.regs = hptiop_map_pci_bar(hba, 0);
4799bcf0910SHarvey Harrison 	if (hba->u.mv.regs == NULL)
48000f59701SHighPoint Linux Team 		return -1;
48100f59701SHighPoint Linux Team 
48200f59701SHighPoint Linux Team 	hba->u.mv.mu = hptiop_map_pci_bar(hba, 2);
4839bcf0910SHarvey Harrison 	if (hba->u.mv.mu == NULL) {
48400f59701SHighPoint Linux Team 		iounmap(hba->u.mv.regs);
48500f59701SHighPoint Linux Team 		return -1;
48600f59701SHighPoint Linux Team 	}
48700f59701SHighPoint Linux Team 
488ede1e6f8SHighPoint Linux Team 	return 0;
489ede1e6f8SHighPoint Linux Team }
490ede1e6f8SHighPoint Linux Team 
49100f59701SHighPoint Linux Team static void hptiop_unmap_pci_bar_mv(struct hptiop_hba *hba)
49200f59701SHighPoint Linux Team {
49300f59701SHighPoint Linux Team 	iounmap(hba->u.mv.regs);
49400f59701SHighPoint Linux Team 	iounmap(hba->u.mv.mu);
49500f59701SHighPoint Linux Team }
49600f59701SHighPoint Linux Team 
497ede1e6f8SHighPoint Linux Team static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg)
498ede1e6f8SHighPoint Linux Team {
499ede1e6f8SHighPoint Linux Team 	dprintk("iop message 0x%x\n", msg);
500ede1e6f8SHighPoint Linux Team 
50100f59701SHighPoint Linux Team 	if (msg == IOPMU_INBOUND_MSG0_NOP)
50200f59701SHighPoint Linux Team 		hba->msg_done = 1;
50300f59701SHighPoint Linux Team 
504ede1e6f8SHighPoint Linux Team 	if (!hba->initialized)
505ede1e6f8SHighPoint Linux Team 		return;
506ede1e6f8SHighPoint Linux Team 
507ede1e6f8SHighPoint Linux Team 	if (msg == IOPMU_INBOUND_MSG0_RESET) {
508ede1e6f8SHighPoint Linux Team 		atomic_set(&hba->resetting, 0);
509ede1e6f8SHighPoint Linux Team 		wake_up(&hba->reset_wq);
510ede1e6f8SHighPoint Linux Team 	}
511ede1e6f8SHighPoint Linux Team 	else if (msg <= IOPMU_INBOUND_MSG0_MAX)
512ede1e6f8SHighPoint Linux Team 		hba->msg_done = 1;
513ede1e6f8SHighPoint Linux Team }
514ede1e6f8SHighPoint Linux Team 
51500f59701SHighPoint Linux Team static struct hptiop_request *get_req(struct hptiop_hba *hba)
516ede1e6f8SHighPoint Linux Team {
517ede1e6f8SHighPoint Linux Team 	struct hptiop_request *ret;
518ede1e6f8SHighPoint Linux Team 
519ede1e6f8SHighPoint Linux Team 	dprintk("get_req : req=%p\n", hba->req_list);
520ede1e6f8SHighPoint Linux Team 
521ede1e6f8SHighPoint Linux Team 	ret = hba->req_list;
522ede1e6f8SHighPoint Linux Team 	if (ret)
523ede1e6f8SHighPoint Linux Team 		hba->req_list = ret->next;
524ede1e6f8SHighPoint Linux Team 
525ede1e6f8SHighPoint Linux Team 	return ret;
526ede1e6f8SHighPoint Linux Team }
527ede1e6f8SHighPoint Linux Team 
52800f59701SHighPoint Linux Team static void free_req(struct hptiop_hba *hba, struct hptiop_request *req)
529ede1e6f8SHighPoint Linux Team {
530ede1e6f8SHighPoint Linux Team 	dprintk("free_req(%d, %p)\n", req->index, req);
531ede1e6f8SHighPoint Linux Team 	req->next = hba->req_list;
532ede1e6f8SHighPoint Linux Team 	hba->req_list = req;
533ede1e6f8SHighPoint Linux Team }
534ede1e6f8SHighPoint Linux Team 
53500f59701SHighPoint Linux Team static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
53600f59701SHighPoint Linux Team 				struct hpt_iop_request_scsi_command *req)
537ede1e6f8SHighPoint Linux Team {
538ede1e6f8SHighPoint Linux Team 	struct scsi_cmnd *scp;
539ede1e6f8SHighPoint Linux Team 
54000f59701SHighPoint Linux Team 	dprintk("hptiop_finish_scsi_req: req=%p, type=%d, "
541ede1e6f8SHighPoint Linux Team 			"result=%d, context=0x%x tag=%d\n",
542ede1e6f8SHighPoint Linux Team 			req, req->header.type, req->header.result,
543ede1e6f8SHighPoint Linux Team 			req->header.context, tag);
544ede1e6f8SHighPoint Linux Team 
545ede1e6f8SHighPoint Linux Team 	BUG_ON(!req->header.result);
546ede1e6f8SHighPoint Linux Team 	BUG_ON(req->header.type != cpu_to_le32(IOP_REQUEST_TYPE_SCSI_COMMAND));
547ede1e6f8SHighPoint Linux Team 
548ede1e6f8SHighPoint Linux Team 	scp = hba->reqs[tag].scp;
549ede1e6f8SHighPoint Linux Team 
550f9875496SFUJITA Tomonori 	if (HPT_SCP(scp)->mapped)
551f9875496SFUJITA Tomonori 		scsi_dma_unmap(scp);
552ede1e6f8SHighPoint Linux Team 
553ede1e6f8SHighPoint Linux Team 	switch (le32_to_cpu(req->header.result)) {
554ede1e6f8SHighPoint Linux Team 	case IOP_RESULT_SUCCESS:
55500f59701SHighPoint Linux Team 		scsi_set_resid(scp,
55600f59701SHighPoint Linux Team 			scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
557ede1e6f8SHighPoint Linux Team 		scp->result = (DID_OK<<16);
558ede1e6f8SHighPoint Linux Team 		break;
559ede1e6f8SHighPoint Linux Team 	case IOP_RESULT_BAD_TARGET:
560ede1e6f8SHighPoint Linux Team 		scp->result = (DID_BAD_TARGET<<16);
561ede1e6f8SHighPoint Linux Team 		break;
562ede1e6f8SHighPoint Linux Team 	case IOP_RESULT_BUSY:
563ede1e6f8SHighPoint Linux Team 		scp->result = (DID_BUS_BUSY<<16);
564ede1e6f8SHighPoint Linux Team 		break;
565ede1e6f8SHighPoint Linux Team 	case IOP_RESULT_RESET:
566ede1e6f8SHighPoint Linux Team 		scp->result = (DID_RESET<<16);
567ede1e6f8SHighPoint Linux Team 		break;
568ede1e6f8SHighPoint Linux Team 	case IOP_RESULT_FAIL:
569ede1e6f8SHighPoint Linux Team 		scp->result = (DID_ERROR<<16);
570ede1e6f8SHighPoint Linux Team 		break;
571ede1e6f8SHighPoint Linux Team 	case IOP_RESULT_INVALID_REQUEST:
572ede1e6f8SHighPoint Linux Team 		scp->result = (DID_ABORT<<16);
573ede1e6f8SHighPoint Linux Team 		break;
57400f59701SHighPoint Linux Team 	case IOP_RESULT_CHECK_CONDITION:
57500f59701SHighPoint Linux Team 		scsi_set_resid(scp,
57600f59701SHighPoint Linux Team 			scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
577ede1e6f8SHighPoint Linux Team 		scp->result = SAM_STAT_CHECK_CONDITION;
578c372f4a8SFUJITA Tomonori 		memcpy(scp->sense_buffer, &req->sg_list,
579b80ca4f7SFUJITA Tomonori 				min_t(size_t, SCSI_SENSE_BUFFERSIZE,
5800fec02c9SHighPoint Linux Team 					le32_to_cpu(req->dataxfer_length)));
581ede1e6f8SHighPoint Linux Team 		break;
582ede1e6f8SHighPoint Linux Team 
583ede1e6f8SHighPoint Linux Team 	default:
584ede1e6f8SHighPoint Linux Team 		scp->result = ((DRIVER_INVALID|SUGGEST_ABORT)<<24) |
585ede1e6f8SHighPoint Linux Team 					(DID_ABORT<<16);
586ede1e6f8SHighPoint Linux Team 		break;
587ede1e6f8SHighPoint Linux Team 	}
588ede1e6f8SHighPoint Linux Team 
589ede1e6f8SHighPoint Linux Team 	dprintk("scsi_done(%p)\n", scp);
590ede1e6f8SHighPoint Linux Team 	scp->scsi_done(scp);
591ede1e6f8SHighPoint Linux Team 	free_req(hba, &hba->reqs[tag]);
592ede1e6f8SHighPoint Linux Team }
593ede1e6f8SHighPoint Linux Team 
59400f59701SHighPoint Linux Team static void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 _tag)
59500f59701SHighPoint Linux Team {
59600f59701SHighPoint Linux Team 	struct hpt_iop_request_scsi_command *req;
59700f59701SHighPoint Linux Team 	u32 tag;
59800f59701SHighPoint Linux Team 
59900f59701SHighPoint Linux Team 	if (hba->iopintf_v2) {
60000f59701SHighPoint Linux Team 		tag = _tag & ~IOPMU_QUEUE_REQUEST_RESULT_BIT;
60100f59701SHighPoint Linux Team 		req = hba->reqs[tag].req_virt;
60200f59701SHighPoint Linux Team 		if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT))
60300f59701SHighPoint Linux Team 			req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS);
60400f59701SHighPoint Linux Team 	} else {
60500f59701SHighPoint Linux Team 		tag = _tag;
60600f59701SHighPoint Linux Team 		req = hba->reqs[tag].req_virt;
60700f59701SHighPoint Linux Team 	}
60800f59701SHighPoint Linux Team 
60900f59701SHighPoint Linux Team 	hptiop_finish_scsi_req(hba, tag, req);
61000f59701SHighPoint Linux Team }
61100f59701SHighPoint Linux Team 
61200f59701SHighPoint Linux Team void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag)
613ede1e6f8SHighPoint Linux Team {
614ede1e6f8SHighPoint Linux Team 	struct hpt_iop_request_header __iomem *req;
615ede1e6f8SHighPoint Linux Team 	struct hpt_iop_request_ioctl_command __iomem *p;
616ede1e6f8SHighPoint Linux Team 	struct hpt_ioctl_k *arg;
617ede1e6f8SHighPoint Linux Team 
618ede1e6f8SHighPoint Linux Team 	req = (struct hpt_iop_request_header __iomem *)
61900f59701SHighPoint Linux Team 			((unsigned long)hba->u.itl.iop + tag);
62000f59701SHighPoint Linux Team 	dprintk("hptiop_iop_request_callback_itl: req=%p, type=%d, "
621ede1e6f8SHighPoint Linux Team 			"result=%d, context=0x%x tag=%d\n",
622ede1e6f8SHighPoint Linux Team 			req, readl(&req->type), readl(&req->result),
623ede1e6f8SHighPoint Linux Team 			readl(&req->context), tag);
624ede1e6f8SHighPoint Linux Team 
625ede1e6f8SHighPoint Linux Team 	BUG_ON(!readl(&req->result));
626ede1e6f8SHighPoint Linux Team 	BUG_ON(readl(&req->type) != IOP_REQUEST_TYPE_IOCTL_COMMAND);
627ede1e6f8SHighPoint Linux Team 
628ede1e6f8SHighPoint Linux Team 	p = (struct hpt_iop_request_ioctl_command __iomem *)req;
629ede1e6f8SHighPoint Linux Team 	arg = (struct hpt_ioctl_k *)(unsigned long)
630ede1e6f8SHighPoint Linux Team 		(readl(&req->context) |
631ede1e6f8SHighPoint Linux Team 			((u64)readl(&req->context_hi32)<<32));
632ede1e6f8SHighPoint Linux Team 
633ede1e6f8SHighPoint Linux Team 	if (readl(&req->result) == IOP_RESULT_SUCCESS) {
634ede1e6f8SHighPoint Linux Team 		arg->result = HPT_IOCTL_RESULT_OK;
635ede1e6f8SHighPoint Linux Team 
636ede1e6f8SHighPoint Linux Team 		if (arg->outbuf_size)
637ede1e6f8SHighPoint Linux Team 			memcpy_fromio(arg->outbuf,
638ede1e6f8SHighPoint Linux Team 				&p->buf[(readl(&p->inbuf_size) + 3)& ~3],
639ede1e6f8SHighPoint Linux Team 				arg->outbuf_size);
640ede1e6f8SHighPoint Linux Team 
641ede1e6f8SHighPoint Linux Team 		if (arg->bytes_returned)
642ede1e6f8SHighPoint Linux Team 			*arg->bytes_returned = arg->outbuf_size;
643ede1e6f8SHighPoint Linux Team 	}
644ede1e6f8SHighPoint Linux Team 	else
645ede1e6f8SHighPoint Linux Team 		arg->result = HPT_IOCTL_RESULT_FAILED;
646ede1e6f8SHighPoint Linux Team 
647ede1e6f8SHighPoint Linux Team 	arg->done(arg);
64800f59701SHighPoint Linux Team 	writel(tag, &hba->u.itl.iop->outbound_queue);
649ede1e6f8SHighPoint Linux Team }
650ede1e6f8SHighPoint Linux Team 
6517d12e780SDavid Howells static irqreturn_t hptiop_intr(int irq, void *dev_id)
652ede1e6f8SHighPoint Linux Team {
653ede1e6f8SHighPoint Linux Team 	struct hptiop_hba  *hba = dev_id;
654ede1e6f8SHighPoint Linux Team 	int  handled;
655ede1e6f8SHighPoint Linux Team 	unsigned long flags;
656ede1e6f8SHighPoint Linux Team 
657ede1e6f8SHighPoint Linux Team 	spin_lock_irqsave(hba->host->host_lock, flags);
65800f59701SHighPoint Linux Team 	handled = hba->ops->iop_intr(hba);
659ede1e6f8SHighPoint Linux Team 	spin_unlock_irqrestore(hba->host->host_lock, flags);
660ede1e6f8SHighPoint Linux Team 
661ede1e6f8SHighPoint Linux Team 	return handled;
662ede1e6f8SHighPoint Linux Team }
663ede1e6f8SHighPoint Linux Team 
664ede1e6f8SHighPoint Linux Team static int hptiop_buildsgl(struct scsi_cmnd *scp, struct hpt_iopsg *psg)
665ede1e6f8SHighPoint Linux Team {
666ede1e6f8SHighPoint Linux Team 	struct Scsi_Host *host = scp->device->host;
667ede1e6f8SHighPoint Linux Team 	struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
668f9875496SFUJITA Tomonori 	struct scatterlist *sg;
669f9875496SFUJITA Tomonori 	int idx, nseg;
670ede1e6f8SHighPoint Linux Team 
671f9875496SFUJITA Tomonori 	nseg = scsi_dma_map(scp);
672f9875496SFUJITA Tomonori 	BUG_ON(nseg < 0);
673f9875496SFUJITA Tomonori 	if (!nseg)
674f9875496SFUJITA Tomonori 		return 0;
675ede1e6f8SHighPoint Linux Team 
676f9875496SFUJITA Tomonori 	HPT_SCP(scp)->sgcnt = nseg;
677ede1e6f8SHighPoint Linux Team 	HPT_SCP(scp)->mapped = 1;
678f9875496SFUJITA Tomonori 
679ede1e6f8SHighPoint Linux Team 	BUG_ON(HPT_SCP(scp)->sgcnt > hba->max_sg_descriptors);
680ede1e6f8SHighPoint Linux Team 
681f9875496SFUJITA Tomonori 	scsi_for_each_sg(scp, sg, HPT_SCP(scp)->sgcnt, idx) {
682f9875496SFUJITA Tomonori 		psg[idx].pci_address = cpu_to_le64(sg_dma_address(sg));
683f9875496SFUJITA Tomonori 		psg[idx].size = cpu_to_le32(sg_dma_len(sg));
684ede1e6f8SHighPoint Linux Team 		psg[idx].eot = (idx == HPT_SCP(scp)->sgcnt - 1) ?
685ede1e6f8SHighPoint Linux Team 			cpu_to_le32(1) : 0;
686ede1e6f8SHighPoint Linux Team 	}
687ede1e6f8SHighPoint Linux Team 	return HPT_SCP(scp)->sgcnt;
688ede1e6f8SHighPoint Linux Team }
689ede1e6f8SHighPoint Linux Team 
69000f59701SHighPoint Linux Team static void hptiop_post_req_itl(struct hptiop_hba *hba,
69100f59701SHighPoint Linux Team 					struct hptiop_request *_req)
69200f59701SHighPoint Linux Team {
69300f59701SHighPoint Linux Team 	struct hpt_iop_request_header *reqhdr = _req->req_virt;
69400f59701SHighPoint Linux Team 
69500f59701SHighPoint Linux Team 	reqhdr->context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT |
69600f59701SHighPoint Linux Team 							(u32)_req->index);
69700f59701SHighPoint Linux Team 	reqhdr->context_hi32 = 0;
69800f59701SHighPoint Linux Team 
69900f59701SHighPoint Linux Team 	if (hba->iopintf_v2) {
70000f59701SHighPoint Linux Team 		u32 size, size_bits;
70100f59701SHighPoint Linux Team 
70200f59701SHighPoint Linux Team 		size = le32_to_cpu(reqhdr->size);
70300f59701SHighPoint Linux Team 		if (size < 256)
70400f59701SHighPoint Linux Team 			size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
70500f59701SHighPoint Linux Team 		else if (size < 512)
70600f59701SHighPoint Linux Team 			size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
70700f59701SHighPoint Linux Team 		else
70800f59701SHighPoint Linux Team 			size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT |
70900f59701SHighPoint Linux Team 						IOPMU_QUEUE_ADDR_HOST_BIT;
71000f59701SHighPoint Linux Team 		writel(_req->req_shifted_phy | size_bits,
71100f59701SHighPoint Linux Team 			&hba->u.itl.iop->inbound_queue);
71200f59701SHighPoint Linux Team 	} else
71300f59701SHighPoint Linux Team 		writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT,
71400f59701SHighPoint Linux Team 					&hba->u.itl.iop->inbound_queue);
71500f59701SHighPoint Linux Team }
71600f59701SHighPoint Linux Team 
71700f59701SHighPoint Linux Team static void hptiop_post_req_mv(struct hptiop_hba *hba,
71800f59701SHighPoint Linux Team 					struct hptiop_request *_req)
71900f59701SHighPoint Linux Team {
72000f59701SHighPoint Linux Team 	struct hpt_iop_request_header *reqhdr = _req->req_virt;
72100f59701SHighPoint Linux Team 	u32 size, size_bit;
72200f59701SHighPoint Linux Team 
72300f59701SHighPoint Linux Team 	reqhdr->context = cpu_to_le32(_req->index<<8 |
72400f59701SHighPoint Linux Team 					IOP_REQUEST_TYPE_SCSI_COMMAND<<5);
72500f59701SHighPoint Linux Team 	reqhdr->context_hi32 = 0;
72600f59701SHighPoint Linux Team 	size = le32_to_cpu(reqhdr->size);
72700f59701SHighPoint Linux Team 
72800f59701SHighPoint Linux Team 	if (size <= 256)
72900f59701SHighPoint Linux Team 		size_bit = 0;
73000f59701SHighPoint Linux Team 	else if (size <= 256*2)
73100f59701SHighPoint Linux Team 		size_bit = 1;
73200f59701SHighPoint Linux Team 	else if (size <= 256*3)
73300f59701SHighPoint Linux Team 		size_bit = 2;
73400f59701SHighPoint Linux Team 	else
73500f59701SHighPoint Linux Team 		size_bit = 3;
73600f59701SHighPoint Linux Team 
73700f59701SHighPoint Linux Team 	mv_inbound_write((_req->req_shifted_phy << 5) |
73800f59701SHighPoint Linux Team 		MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bit, hba);
73900f59701SHighPoint Linux Team }
74000f59701SHighPoint Linux Team 
741ede1e6f8SHighPoint Linux Team static int hptiop_queuecommand(struct scsi_cmnd *scp,
742ede1e6f8SHighPoint Linux Team 				void (*done)(struct scsi_cmnd *))
743ede1e6f8SHighPoint Linux Team {
744ede1e6f8SHighPoint Linux Team 	struct Scsi_Host *host = scp->device->host;
745ede1e6f8SHighPoint Linux Team 	struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
746ede1e6f8SHighPoint Linux Team 	struct hpt_iop_request_scsi_command *req;
747ede1e6f8SHighPoint Linux Team 	int sg_count = 0;
748ede1e6f8SHighPoint Linux Team 	struct hptiop_request *_req;
749ede1e6f8SHighPoint Linux Team 
750ede1e6f8SHighPoint Linux Team 	BUG_ON(!done);
751ede1e6f8SHighPoint Linux Team 	scp->scsi_done = done;
752ede1e6f8SHighPoint Linux Team 
753ede1e6f8SHighPoint Linux Team 	_req = get_req(hba);
754ede1e6f8SHighPoint Linux Team 	if (_req == NULL) {
755ede1e6f8SHighPoint Linux Team 		dprintk("hptiop_queuecmd : no free req\n");
7564f2ddba3SHighPoint Linux Team 		return SCSI_MLQUEUE_HOST_BUSY;
757ede1e6f8SHighPoint Linux Team 	}
758ede1e6f8SHighPoint Linux Team 
759ede1e6f8SHighPoint Linux Team 	_req->scp = scp;
760ede1e6f8SHighPoint Linux Team 
761ede1e6f8SHighPoint Linux Team 	dprintk("hptiop_queuecmd(scp=%p) %d/%d/%d/%d cdb=(%x-%x-%x) "
762ede1e6f8SHighPoint Linux Team 			"req_index=%d, req=%p\n",
763ede1e6f8SHighPoint Linux Team 			scp,
764ede1e6f8SHighPoint Linux Team 			host->host_no, scp->device->channel,
765ede1e6f8SHighPoint Linux Team 			scp->device->id, scp->device->lun,
76664a87b24SBoaz Harrosh 			((u32 *)scp->cmnd)[0],
76764a87b24SBoaz Harrosh 			((u32 *)scp->cmnd)[1],
76864a87b24SBoaz Harrosh 			((u32 *)scp->cmnd)[2],
769ede1e6f8SHighPoint Linux Team 			_req->index, _req->req_virt);
770ede1e6f8SHighPoint Linux Team 
771ede1e6f8SHighPoint Linux Team 	scp->result = 0;
772ede1e6f8SHighPoint Linux Team 
773ede1e6f8SHighPoint Linux Team 	if (scp->device->channel || scp->device->lun ||
774ede1e6f8SHighPoint Linux Team 			scp->device->id > hba->max_devices) {
775ede1e6f8SHighPoint Linux Team 		scp->result = DID_BAD_TARGET << 16;
776ede1e6f8SHighPoint Linux Team 		free_req(hba, _req);
777ede1e6f8SHighPoint Linux Team 		goto cmd_done;
778ede1e6f8SHighPoint Linux Team 	}
779ede1e6f8SHighPoint Linux Team 
780db9b6e89SHighPoint Linux Team 	req = _req->req_virt;
781ede1e6f8SHighPoint Linux Team 
782ede1e6f8SHighPoint Linux Team 	/* build S/G table */
783ede1e6f8SHighPoint Linux Team 	sg_count = hptiop_buildsgl(scp, req->sg_list);
784f9875496SFUJITA Tomonori 	if (!sg_count)
785ede1e6f8SHighPoint Linux Team 		HPT_SCP(scp)->mapped = 0;
786ede1e6f8SHighPoint Linux Team 
787ede1e6f8SHighPoint Linux Team 	req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
788ede1e6f8SHighPoint Linux Team 	req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SCSI_COMMAND);
789ede1e6f8SHighPoint Linux Team 	req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
790f9875496SFUJITA Tomonori 	req->dataxfer_length = cpu_to_le32(scsi_bufflen(scp));
791ede1e6f8SHighPoint Linux Team 	req->channel = scp->device->channel;
792ede1e6f8SHighPoint Linux Team 	req->target = scp->device->id;
793ede1e6f8SHighPoint Linux Team 	req->lun = scp->device->lun;
794ede1e6f8SHighPoint Linux Team 	req->header.size = cpu_to_le32(
795ede1e6f8SHighPoint Linux Team 				sizeof(struct hpt_iop_request_scsi_command)
796ede1e6f8SHighPoint Linux Team 				 - sizeof(struct hpt_iopsg)
797ede1e6f8SHighPoint Linux Team 				 + sg_count * sizeof(struct hpt_iopsg));
798ede1e6f8SHighPoint Linux Team 
799ede1e6f8SHighPoint Linux Team 	memcpy(req->cdb, scp->cmnd, sizeof(req->cdb));
80000f59701SHighPoint Linux Team 	hba->ops->post_req(hba, _req);
801ede1e6f8SHighPoint Linux Team 	return 0;
802ede1e6f8SHighPoint Linux Team 
803ede1e6f8SHighPoint Linux Team cmd_done:
804ede1e6f8SHighPoint Linux Team 	dprintk("scsi_done(scp=%p)\n", scp);
805ede1e6f8SHighPoint Linux Team 	scp->scsi_done(scp);
806ede1e6f8SHighPoint Linux Team 	return 0;
807ede1e6f8SHighPoint Linux Team }
808ede1e6f8SHighPoint Linux Team 
809ede1e6f8SHighPoint Linux Team static const char *hptiop_info(struct Scsi_Host *host)
810ede1e6f8SHighPoint Linux Team {
811ede1e6f8SHighPoint Linux Team 	return driver_name_long;
812ede1e6f8SHighPoint Linux Team }
813ede1e6f8SHighPoint Linux Team 
814ede1e6f8SHighPoint Linux Team static int hptiop_reset_hba(struct hptiop_hba *hba)
815ede1e6f8SHighPoint Linux Team {
816ede1e6f8SHighPoint Linux Team 	if (atomic_xchg(&hba->resetting, 1) == 0) {
817ede1e6f8SHighPoint Linux Team 		atomic_inc(&hba->reset_count);
81800f59701SHighPoint Linux Team 		hba->ops->post_msg(hba, IOPMU_INBOUND_MSG0_RESET);
819ede1e6f8SHighPoint Linux Team 	}
820ede1e6f8SHighPoint Linux Team 
821ede1e6f8SHighPoint Linux Team 	wait_event_timeout(hba->reset_wq,
822ede1e6f8SHighPoint Linux Team 			atomic_read(&hba->resetting) == 0, 60 * HZ);
823ede1e6f8SHighPoint Linux Team 
824ede1e6f8SHighPoint Linux Team 	if (atomic_read(&hba->resetting)) {
825ede1e6f8SHighPoint Linux Team 		/* IOP is in unkown state, abort reset */
826ede1e6f8SHighPoint Linux Team 		printk(KERN_ERR "scsi%d: reset failed\n", hba->host->host_no);
827ede1e6f8SHighPoint Linux Team 		return -1;
828ede1e6f8SHighPoint Linux Team 	}
829ede1e6f8SHighPoint Linux Team 
830ede1e6f8SHighPoint Linux Team 	if (iop_send_sync_msg(hba,
831ede1e6f8SHighPoint Linux Team 		IOPMU_INBOUND_MSG0_START_BACKGROUND_TASK, 5000)) {
832ede1e6f8SHighPoint Linux Team 		dprintk("scsi%d: fail to start background task\n",
833ede1e6f8SHighPoint Linux Team 				hba->host->host_no);
834ede1e6f8SHighPoint Linux Team 	}
835ede1e6f8SHighPoint Linux Team 
836ede1e6f8SHighPoint Linux Team 	return 0;
837ede1e6f8SHighPoint Linux Team }
838ede1e6f8SHighPoint Linux Team 
839ede1e6f8SHighPoint Linux Team static int hptiop_reset(struct scsi_cmnd *scp)
840ede1e6f8SHighPoint Linux Team {
841ede1e6f8SHighPoint Linux Team 	struct Scsi_Host * host = scp->device->host;
842ede1e6f8SHighPoint Linux Team 	struct hptiop_hba * hba = (struct hptiop_hba *)host->hostdata;
843ede1e6f8SHighPoint Linux Team 
844ede1e6f8SHighPoint Linux Team 	printk(KERN_WARNING "hptiop_reset(%d/%d/%d) scp=%p\n",
845ede1e6f8SHighPoint Linux Team 			scp->device->host->host_no, scp->device->channel,
846ede1e6f8SHighPoint Linux Team 			scp->device->id, scp);
847ede1e6f8SHighPoint Linux Team 
848ede1e6f8SHighPoint Linux Team 	return hptiop_reset_hba(hba)? FAILED : SUCCESS;
849ede1e6f8SHighPoint Linux Team }
850ede1e6f8SHighPoint Linux Team 
851ede1e6f8SHighPoint Linux Team static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev,
852ede1e6f8SHighPoint Linux Team 						int queue_depth)
853ede1e6f8SHighPoint Linux Team {
85400f59701SHighPoint Linux Team 	struct hptiop_hba *hba = (struct hptiop_hba *)sdev->host->hostdata;
85500f59701SHighPoint Linux Team 
85600f59701SHighPoint Linux Team 	if (queue_depth > hba->max_requests)
85700f59701SHighPoint Linux Team 		queue_depth = hba->max_requests;
858ede1e6f8SHighPoint Linux Team 	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
859ede1e6f8SHighPoint Linux Team 	return queue_depth;
860ede1e6f8SHighPoint Linux Team }
861ede1e6f8SHighPoint Linux Team 
862ee959b00STony Jones static ssize_t hptiop_show_version(struct device *dev,
863ee959b00STony Jones 				   struct device_attribute *attr, char *buf)
864ede1e6f8SHighPoint Linux Team {
865ede1e6f8SHighPoint Linux Team 	return snprintf(buf, PAGE_SIZE, "%s\n", driver_ver);
866ede1e6f8SHighPoint Linux Team }
867ede1e6f8SHighPoint Linux Team 
868ee959b00STony Jones static ssize_t hptiop_show_fw_version(struct device *dev,
869ee959b00STony Jones 				      struct device_attribute *attr, char *buf)
870ede1e6f8SHighPoint Linux Team {
871ee959b00STony Jones 	struct Scsi_Host *host = class_to_shost(dev);
872ede1e6f8SHighPoint Linux Team 	struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
873ede1e6f8SHighPoint Linux Team 
874ede1e6f8SHighPoint Linux Team 	return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n",
875ede1e6f8SHighPoint Linux Team 				hba->firmware_version >> 24,
876ede1e6f8SHighPoint Linux Team 				(hba->firmware_version >> 16) & 0xff,
877ede1e6f8SHighPoint Linux Team 				(hba->firmware_version >> 8) & 0xff,
878ede1e6f8SHighPoint Linux Team 				hba->firmware_version & 0xff);
879ede1e6f8SHighPoint Linux Team }
880ede1e6f8SHighPoint Linux Team 
881ee959b00STony Jones static struct device_attribute hptiop_attr_version = {
882ede1e6f8SHighPoint Linux Team 	.attr = {
883ede1e6f8SHighPoint Linux Team 		.name = "driver-version",
884ede1e6f8SHighPoint Linux Team 		.mode = S_IRUGO,
885ede1e6f8SHighPoint Linux Team 	},
886ede1e6f8SHighPoint Linux Team 	.show = hptiop_show_version,
887ede1e6f8SHighPoint Linux Team };
888ede1e6f8SHighPoint Linux Team 
889ee959b00STony Jones static struct device_attribute hptiop_attr_fw_version = {
890ede1e6f8SHighPoint Linux Team 	.attr = {
891ede1e6f8SHighPoint Linux Team 		.name = "firmware-version",
892ede1e6f8SHighPoint Linux Team 		.mode = S_IRUGO,
893ede1e6f8SHighPoint Linux Team 	},
894ede1e6f8SHighPoint Linux Team 	.show = hptiop_show_fw_version,
895ede1e6f8SHighPoint Linux Team };
896ede1e6f8SHighPoint Linux Team 
897ee959b00STony Jones static struct device_attribute *hptiop_attrs[] = {
898ede1e6f8SHighPoint Linux Team 	&hptiop_attr_version,
899ede1e6f8SHighPoint Linux Team 	&hptiop_attr_fw_version,
900ede1e6f8SHighPoint Linux Team 	NULL
901ede1e6f8SHighPoint Linux Team };
902ede1e6f8SHighPoint Linux Team 
903ede1e6f8SHighPoint Linux Team static struct scsi_host_template driver_template = {
904ede1e6f8SHighPoint Linux Team 	.module                     = THIS_MODULE,
905ede1e6f8SHighPoint Linux Team 	.name                       = driver_name,
906ede1e6f8SHighPoint Linux Team 	.queuecommand               = hptiop_queuecommand,
907ede1e6f8SHighPoint Linux Team 	.eh_device_reset_handler    = hptiop_reset,
908ede1e6f8SHighPoint Linux Team 	.eh_bus_reset_handler       = hptiop_reset,
909ede1e6f8SHighPoint Linux Team 	.info                       = hptiop_info,
910ede1e6f8SHighPoint Linux Team 	.emulated                   = 0,
911ede1e6f8SHighPoint Linux Team 	.use_clustering             = ENABLE_CLUSTERING,
912ede1e6f8SHighPoint Linux Team 	.proc_name                  = driver_name,
913ede1e6f8SHighPoint Linux Team 	.shost_attrs                = hptiop_attrs,
914ede1e6f8SHighPoint Linux Team 	.this_id                    = -1,
915ede1e6f8SHighPoint Linux Team 	.change_queue_depth         = hptiop_adjust_disk_queue_depth,
916ede1e6f8SHighPoint Linux Team };
917ede1e6f8SHighPoint Linux Team 
91800f59701SHighPoint Linux Team static int hptiop_internal_memalloc_mv(struct hptiop_hba *hba)
91900f59701SHighPoint Linux Team {
92000f59701SHighPoint Linux Team 	hba->u.mv.internal_req = dma_alloc_coherent(&hba->pcidev->dev,
92100f59701SHighPoint Linux Team 			0x800, &hba->u.mv.internal_req_phy, GFP_KERNEL);
92200f59701SHighPoint Linux Team 	if (hba->u.mv.internal_req)
92300f59701SHighPoint Linux Team 		return 0;
92400f59701SHighPoint Linux Team 	else
92500f59701SHighPoint Linux Team 		return -1;
92600f59701SHighPoint Linux Team }
92700f59701SHighPoint Linux Team 
92800f59701SHighPoint Linux Team static int hptiop_internal_memfree_mv(struct hptiop_hba *hba)
92900f59701SHighPoint Linux Team {
93000f59701SHighPoint Linux Team 	if (hba->u.mv.internal_req) {
93100f59701SHighPoint Linux Team 		dma_free_coherent(&hba->pcidev->dev, 0x800,
93200f59701SHighPoint Linux Team 			hba->u.mv.internal_req, hba->u.mv.internal_req_phy);
93300f59701SHighPoint Linux Team 		return 0;
93400f59701SHighPoint Linux Team 	} else
93500f59701SHighPoint Linux Team 		return -1;
93600f59701SHighPoint Linux Team }
93700f59701SHighPoint Linux Team 
938ede1e6f8SHighPoint Linux Team static int __devinit hptiop_probe(struct pci_dev *pcidev,
939ede1e6f8SHighPoint Linux Team 					const struct pci_device_id *id)
940ede1e6f8SHighPoint Linux Team {
941ede1e6f8SHighPoint Linux Team 	struct Scsi_Host *host = NULL;
942ede1e6f8SHighPoint Linux Team 	struct hptiop_hba *hba;
943ede1e6f8SHighPoint Linux Team 	struct hpt_iop_request_get_config iop_config;
944ede1e6f8SHighPoint Linux Team 	struct hpt_iop_request_set_config set_config;
945ede1e6f8SHighPoint Linux Team 	dma_addr_t start_phy;
946ede1e6f8SHighPoint Linux Team 	void *start_virt;
947ede1e6f8SHighPoint Linux Team 	u32 offset, i, req_size;
948ede1e6f8SHighPoint Linux Team 
949ede1e6f8SHighPoint Linux Team 	dprintk("hptiop_probe(%p)\n", pcidev);
950ede1e6f8SHighPoint Linux Team 
951ede1e6f8SHighPoint Linux Team 	if (pci_enable_device(pcidev)) {
952ede1e6f8SHighPoint Linux Team 		printk(KERN_ERR "hptiop: fail to enable pci device\n");
953ede1e6f8SHighPoint Linux Team 		return -ENODEV;
954ede1e6f8SHighPoint Linux Team 	}
955ede1e6f8SHighPoint Linux Team 
956ede1e6f8SHighPoint Linux Team 	printk(KERN_INFO "adapter at PCI %d:%d:%d, IRQ %d\n",
957ede1e6f8SHighPoint Linux Team 		pcidev->bus->number, pcidev->devfn >> 3, pcidev->devfn & 7,
958ede1e6f8SHighPoint Linux Team 		pcidev->irq);
959ede1e6f8SHighPoint Linux Team 
960ede1e6f8SHighPoint Linux Team 	pci_set_master(pcidev);
961ede1e6f8SHighPoint Linux Team 
962ede1e6f8SHighPoint Linux Team 	/* Enable 64bit DMA if possible */
963ede1e6f8SHighPoint Linux Team 	if (pci_set_dma_mask(pcidev, DMA_64BIT_MASK)) {
964ede1e6f8SHighPoint Linux Team 		if (pci_set_dma_mask(pcidev, DMA_32BIT_MASK)) {
965ede1e6f8SHighPoint Linux Team 			printk(KERN_ERR "hptiop: fail to set dma_mask\n");
966ede1e6f8SHighPoint Linux Team 			goto disable_pci_device;
967ede1e6f8SHighPoint Linux Team 		}
968ede1e6f8SHighPoint Linux Team 	}
969ede1e6f8SHighPoint Linux Team 
970ede1e6f8SHighPoint Linux Team 	if (pci_request_regions(pcidev, driver_name)) {
971ede1e6f8SHighPoint Linux Team 		printk(KERN_ERR "hptiop: pci_request_regions failed\n");
972ede1e6f8SHighPoint Linux Team 		goto disable_pci_device;
973ede1e6f8SHighPoint Linux Team 	}
974ede1e6f8SHighPoint Linux Team 
975ede1e6f8SHighPoint Linux Team 	host = scsi_host_alloc(&driver_template, sizeof(struct hptiop_hba));
976ede1e6f8SHighPoint Linux Team 	if (!host) {
977ede1e6f8SHighPoint Linux Team 		printk(KERN_ERR "hptiop: fail to alloc scsi host\n");
978ede1e6f8SHighPoint Linux Team 		goto free_pci_regions;
979ede1e6f8SHighPoint Linux Team 	}
980ede1e6f8SHighPoint Linux Team 
981ede1e6f8SHighPoint Linux Team 	hba = (struct hptiop_hba *)host->hostdata;
982ede1e6f8SHighPoint Linux Team 
98300f59701SHighPoint Linux Team 	hba->ops = (struct hptiop_adapter_ops *)id->driver_data;
984ede1e6f8SHighPoint Linux Team 	hba->pcidev = pcidev;
985ede1e6f8SHighPoint Linux Team 	hba->host = host;
986ede1e6f8SHighPoint Linux Team 	hba->initialized = 0;
987db9b6e89SHighPoint Linux Team 	hba->iopintf_v2 = 0;
988ede1e6f8SHighPoint Linux Team 
989ede1e6f8SHighPoint Linux Team 	atomic_set(&hba->resetting, 0);
990ede1e6f8SHighPoint Linux Team 	atomic_set(&hba->reset_count, 0);
991ede1e6f8SHighPoint Linux Team 
992ede1e6f8SHighPoint Linux Team 	init_waitqueue_head(&hba->reset_wq);
993ede1e6f8SHighPoint Linux Team 	init_waitqueue_head(&hba->ioctl_wq);
994ede1e6f8SHighPoint Linux Team 
995ede1e6f8SHighPoint Linux Team 	host->max_lun = 1;
996ede1e6f8SHighPoint Linux Team 	host->max_channel = 0;
997ede1e6f8SHighPoint Linux Team 	host->io_port = 0;
998ede1e6f8SHighPoint Linux Team 	host->n_io_port = 0;
999ede1e6f8SHighPoint Linux Team 	host->irq = pcidev->irq;
1000ede1e6f8SHighPoint Linux Team 
100100f59701SHighPoint Linux Team 	if (hba->ops->map_pci_bar(hba))
1002ede1e6f8SHighPoint Linux Team 		goto free_scsi_host;
1003ede1e6f8SHighPoint Linux Team 
100400f59701SHighPoint Linux Team 	if (hba->ops->iop_wait_ready(hba, 20000)) {
1005ede1e6f8SHighPoint Linux Team 		printk(KERN_ERR "scsi%d: firmware not ready\n",
1006ede1e6f8SHighPoint Linux Team 				hba->host->host_no);
1007ede1e6f8SHighPoint Linux Team 		goto unmap_pci_bar;
1008ede1e6f8SHighPoint Linux Team 	}
1009ede1e6f8SHighPoint Linux Team 
101000f59701SHighPoint Linux Team 	if (hba->ops->internal_memalloc) {
101100f59701SHighPoint Linux Team 		if (hba->ops->internal_memalloc(hba)) {
101200f59701SHighPoint Linux Team 			printk(KERN_ERR "scsi%d: internal_memalloc failed\n",
101300f59701SHighPoint Linux Team 				hba->host->host_no);
101400f59701SHighPoint Linux Team 			goto unmap_pci_bar;
101500f59701SHighPoint Linux Team 		}
101600f59701SHighPoint Linux Team 	}
101700f59701SHighPoint Linux Team 
101800f59701SHighPoint Linux Team 	if (hba->ops->get_config(hba, &iop_config)) {
1019ede1e6f8SHighPoint Linux Team 		printk(KERN_ERR "scsi%d: get config failed\n",
1020ede1e6f8SHighPoint Linux Team 				hba->host->host_no);
1021ede1e6f8SHighPoint Linux Team 		goto unmap_pci_bar;
1022ede1e6f8SHighPoint Linux Team 	}
1023ede1e6f8SHighPoint Linux Team 
1024ede1e6f8SHighPoint Linux Team 	hba->max_requests = min(le32_to_cpu(iop_config.max_requests),
1025ede1e6f8SHighPoint Linux Team 				HPTIOP_MAX_REQUESTS);
1026ede1e6f8SHighPoint Linux Team 	hba->max_devices = le32_to_cpu(iop_config.max_devices);
1027ede1e6f8SHighPoint Linux Team 	hba->max_request_size = le32_to_cpu(iop_config.request_size);
1028ede1e6f8SHighPoint Linux Team 	hba->max_sg_descriptors = le32_to_cpu(iop_config.max_sg_count);
1029ede1e6f8SHighPoint Linux Team 	hba->firmware_version = le32_to_cpu(iop_config.firmware_version);
1030db9b6e89SHighPoint Linux Team 	hba->interface_version = le32_to_cpu(iop_config.interface_version);
1031ede1e6f8SHighPoint Linux Team 	hba->sdram_size = le32_to_cpu(iop_config.sdram_size);
1032ede1e6f8SHighPoint Linux Team 
1033db9b6e89SHighPoint Linux Team 	if (hba->firmware_version > 0x01020000 ||
1034db9b6e89SHighPoint Linux Team 			hba->interface_version > 0x01020000)
1035db9b6e89SHighPoint Linux Team 		hba->iopintf_v2 = 1;
1036db9b6e89SHighPoint Linux Team 
1037ede1e6f8SHighPoint Linux Team 	host->max_sectors = le32_to_cpu(iop_config.data_transfer_length) >> 9;
1038ede1e6f8SHighPoint Linux Team 	host->max_id = le32_to_cpu(iop_config.max_devices);
1039ede1e6f8SHighPoint Linux Team 	host->sg_tablesize = le32_to_cpu(iop_config.max_sg_count);
1040ede1e6f8SHighPoint Linux Team 	host->can_queue = le32_to_cpu(iop_config.max_requests);
1041ede1e6f8SHighPoint Linux Team 	host->cmd_per_lun = le32_to_cpu(iop_config.max_requests);
1042ede1e6f8SHighPoint Linux Team 	host->max_cmd_len = 16;
1043ede1e6f8SHighPoint Linux Team 
1044db9b6e89SHighPoint Linux Team 	req_size = sizeof(struct hpt_iop_request_scsi_command)
1045db9b6e89SHighPoint Linux Team 		+ sizeof(struct hpt_iopsg) * (hba->max_sg_descriptors - 1);
1046db9b6e89SHighPoint Linux Team 	if ((req_size & 0x1f) != 0)
1047db9b6e89SHighPoint Linux Team 		req_size = (req_size + 0x1f) & ~0x1f;
1048db9b6e89SHighPoint Linux Team 
1049db9b6e89SHighPoint Linux Team 	memset(&set_config, 0, sizeof(struct hpt_iop_request_set_config));
1050ede1e6f8SHighPoint Linux Team 	set_config.iop_id = cpu_to_le32(host->host_no);
1051db9b6e89SHighPoint Linux Team 	set_config.vbus_id = cpu_to_le16(host->host_no);
1052db9b6e89SHighPoint Linux Team 	set_config.max_host_request_size = cpu_to_le16(req_size);
1053ede1e6f8SHighPoint Linux Team 
105400f59701SHighPoint Linux Team 	if (hba->ops->set_config(hba, &set_config)) {
1055ede1e6f8SHighPoint Linux Team 		printk(KERN_ERR "scsi%d: set config failed\n",
1056ede1e6f8SHighPoint Linux Team 				hba->host->host_no);
1057ede1e6f8SHighPoint Linux Team 		goto unmap_pci_bar;
1058ede1e6f8SHighPoint Linux Team 	}
1059ede1e6f8SHighPoint Linux Team 
1060ede1e6f8SHighPoint Linux Team 	pci_set_drvdata(pcidev, host);
1061ede1e6f8SHighPoint Linux Team 
10621d6f359aSThomas Gleixner 	if (request_irq(pcidev->irq, hptiop_intr, IRQF_SHARED,
1063ede1e6f8SHighPoint Linux Team 					driver_name, hba)) {
1064ede1e6f8SHighPoint Linux Team 		printk(KERN_ERR "scsi%d: request irq %d failed\n",
1065ede1e6f8SHighPoint Linux Team 					hba->host->host_no, pcidev->irq);
10663e74051bSChristoph Hellwig 		goto unmap_pci_bar;
1067ede1e6f8SHighPoint Linux Team 	}
1068ede1e6f8SHighPoint Linux Team 
1069ede1e6f8SHighPoint Linux Team 	/* Allocate request mem */
1070ede1e6f8SHighPoint Linux Team 
1071ede1e6f8SHighPoint Linux Team 	dprintk("req_size=%d, max_requests=%d\n", req_size, hba->max_requests);
1072ede1e6f8SHighPoint Linux Team 
1073ede1e6f8SHighPoint Linux Team 	hba->req_size = req_size;
1074ede1e6f8SHighPoint Linux Team 	start_virt = dma_alloc_coherent(&pcidev->dev,
1075ede1e6f8SHighPoint Linux Team 				hba->req_size*hba->max_requests + 0x20,
1076ede1e6f8SHighPoint Linux Team 				&start_phy, GFP_KERNEL);
1077ede1e6f8SHighPoint Linux Team 
1078ede1e6f8SHighPoint Linux Team 	if (!start_virt) {
1079ede1e6f8SHighPoint Linux Team 		printk(KERN_ERR "scsi%d: fail to alloc request mem\n",
1080ede1e6f8SHighPoint Linux Team 					hba->host->host_no);
1081ede1e6f8SHighPoint Linux Team 		goto free_request_irq;
1082ede1e6f8SHighPoint Linux Team 	}
1083ede1e6f8SHighPoint Linux Team 
1084ede1e6f8SHighPoint Linux Team 	hba->dma_coherent = start_virt;
1085ede1e6f8SHighPoint Linux Team 	hba->dma_coherent_handle = start_phy;
1086ede1e6f8SHighPoint Linux Team 
1087ede1e6f8SHighPoint Linux Team 	if ((start_phy & 0x1f) != 0)
1088ede1e6f8SHighPoint Linux Team 	{
1089ede1e6f8SHighPoint Linux Team 		offset = ((start_phy + 0x1f) & ~0x1f) - start_phy;
1090ede1e6f8SHighPoint Linux Team 		start_phy += offset;
1091ede1e6f8SHighPoint Linux Team 		start_virt += offset;
1092ede1e6f8SHighPoint Linux Team 	}
1093ede1e6f8SHighPoint Linux Team 
1094ede1e6f8SHighPoint Linux Team 	hba->req_list = start_virt;
1095ede1e6f8SHighPoint Linux Team 	for (i = 0; i < hba->max_requests; i++) {
1096ede1e6f8SHighPoint Linux Team 		hba->reqs[i].next = NULL;
1097ede1e6f8SHighPoint Linux Team 		hba->reqs[i].req_virt = start_virt;
1098ede1e6f8SHighPoint Linux Team 		hba->reqs[i].req_shifted_phy = start_phy >> 5;
1099ede1e6f8SHighPoint Linux Team 		hba->reqs[i].index = i;
1100ede1e6f8SHighPoint Linux Team 		free_req(hba, &hba->reqs[i]);
1101ede1e6f8SHighPoint Linux Team 		start_virt = (char *)start_virt + hba->req_size;
1102ede1e6f8SHighPoint Linux Team 		start_phy = start_phy + hba->req_size;
1103ede1e6f8SHighPoint Linux Team 	}
1104ede1e6f8SHighPoint Linux Team 
1105ede1e6f8SHighPoint Linux Team 	/* Enable Interrupt and start background task */
1106ede1e6f8SHighPoint Linux Team 	if (hptiop_initialize_iop(hba))
1107ede1e6f8SHighPoint Linux Team 		goto free_request_mem;
1108ede1e6f8SHighPoint Linux Team 
11093e74051bSChristoph Hellwig 	if (scsi_add_host(host, &pcidev->dev)) {
11103e74051bSChristoph Hellwig 		printk(KERN_ERR "scsi%d: scsi_add_host failed\n",
11113e74051bSChristoph Hellwig 					hba->host->host_no);
11123e74051bSChristoph Hellwig 		goto free_request_mem;
11133e74051bSChristoph Hellwig 	}
11143e74051bSChristoph Hellwig 
1115ede1e6f8SHighPoint Linux Team 
1116ede1e6f8SHighPoint Linux Team 	scsi_scan_host(host);
1117ede1e6f8SHighPoint Linux Team 
1118ede1e6f8SHighPoint Linux Team 	dprintk("scsi%d: hptiop_probe successfully\n", hba->host->host_no);
1119ede1e6f8SHighPoint Linux Team 	return 0;
1120ede1e6f8SHighPoint Linux Team 
1121ede1e6f8SHighPoint Linux Team free_request_mem:
1122ede1e6f8SHighPoint Linux Team 	dma_free_coherent(&hba->pcidev->dev,
1123ede1e6f8SHighPoint Linux Team 			hba->req_size * hba->max_requests + 0x20,
1124ede1e6f8SHighPoint Linux Team 			hba->dma_coherent, hba->dma_coherent_handle);
1125ede1e6f8SHighPoint Linux Team 
1126ede1e6f8SHighPoint Linux Team free_request_irq:
1127ede1e6f8SHighPoint Linux Team 	free_irq(hba->pcidev->irq, hba);
1128ede1e6f8SHighPoint Linux Team 
1129ede1e6f8SHighPoint Linux Team unmap_pci_bar:
113000f59701SHighPoint Linux Team 	if (hba->ops->internal_memfree)
113100f59701SHighPoint Linux Team 		hba->ops->internal_memfree(hba);
1132ede1e6f8SHighPoint Linux Team 
113300f59701SHighPoint Linux Team 	hba->ops->unmap_pci_bar(hba);
1134ede1e6f8SHighPoint Linux Team 
1135ede1e6f8SHighPoint Linux Team free_scsi_host:
1136ede1e6f8SHighPoint Linux Team 	scsi_host_put(host);
1137ede1e6f8SHighPoint Linux Team 
113800f59701SHighPoint Linux Team free_pci_regions:
113900f59701SHighPoint Linux Team 	pci_release_regions(pcidev);
114000f59701SHighPoint Linux Team 
1141ede1e6f8SHighPoint Linux Team disable_pci_device:
1142ede1e6f8SHighPoint Linux Team 	pci_disable_device(pcidev);
1143ede1e6f8SHighPoint Linux Team 
1144ede1e6f8SHighPoint Linux Team 	dprintk("scsi%d: hptiop_probe fail\n", host->host_no);
1145ede1e6f8SHighPoint Linux Team 	return -ENODEV;
1146ede1e6f8SHighPoint Linux Team }
1147ede1e6f8SHighPoint Linux Team 
1148ede1e6f8SHighPoint Linux Team static void hptiop_shutdown(struct pci_dev *pcidev)
1149ede1e6f8SHighPoint Linux Team {
1150ede1e6f8SHighPoint Linux Team 	struct Scsi_Host *host = pci_get_drvdata(pcidev);
1151ede1e6f8SHighPoint Linux Team 	struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
1152ede1e6f8SHighPoint Linux Team 
1153ede1e6f8SHighPoint Linux Team 	dprintk("hptiop_shutdown(%p)\n", hba);
1154ede1e6f8SHighPoint Linux Team 
1155ede1e6f8SHighPoint Linux Team 	/* stop the iop */
1156ede1e6f8SHighPoint Linux Team 	if (iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_SHUTDOWN, 60000))
1157ede1e6f8SHighPoint Linux Team 		printk(KERN_ERR "scsi%d: shutdown the iop timeout\n",
1158ede1e6f8SHighPoint Linux Team 					hba->host->host_no);
1159ede1e6f8SHighPoint Linux Team 
1160ede1e6f8SHighPoint Linux Team 	/* disable all outbound interrupts */
116100f59701SHighPoint Linux Team 	hba->ops->disable_intr(hba);
116200f59701SHighPoint Linux Team }
116300f59701SHighPoint Linux Team 
116400f59701SHighPoint Linux Team static void hptiop_disable_intr_itl(struct hptiop_hba *hba)
116500f59701SHighPoint Linux Team {
116600f59701SHighPoint Linux Team 	u32 int_mask;
116700f59701SHighPoint Linux Team 
116800f59701SHighPoint Linux Team 	int_mask = readl(&hba->u.itl.iop->outbound_intmask);
1169ede1e6f8SHighPoint Linux Team 	writel(int_mask |
1170ede1e6f8SHighPoint Linux Team 		IOPMU_OUTBOUND_INT_MSG0 | IOPMU_OUTBOUND_INT_POSTQUEUE,
117100f59701SHighPoint Linux Team 		&hba->u.itl.iop->outbound_intmask);
117200f59701SHighPoint Linux Team 	readl(&hba->u.itl.iop->outbound_intmask);
117300f59701SHighPoint Linux Team }
117400f59701SHighPoint Linux Team 
117500f59701SHighPoint Linux Team static void hptiop_disable_intr_mv(struct hptiop_hba *hba)
117600f59701SHighPoint Linux Team {
117700f59701SHighPoint Linux Team 	writel(0, &hba->u.mv.regs->outbound_intmask);
117800f59701SHighPoint Linux Team 	readl(&hba->u.mv.regs->outbound_intmask);
1179ede1e6f8SHighPoint Linux Team }
1180ede1e6f8SHighPoint Linux Team 
1181ede1e6f8SHighPoint Linux Team static void hptiop_remove(struct pci_dev *pcidev)
1182ede1e6f8SHighPoint Linux Team {
1183ede1e6f8SHighPoint Linux Team 	struct Scsi_Host *host = pci_get_drvdata(pcidev);
1184ede1e6f8SHighPoint Linux Team 	struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
1185ede1e6f8SHighPoint Linux Team 
1186ede1e6f8SHighPoint Linux Team 	dprintk("scsi%d: hptiop_remove\n", hba->host->host_no);
1187ede1e6f8SHighPoint Linux Team 
11884f2ddba3SHighPoint Linux Team 	scsi_remove_host(host);
11894f2ddba3SHighPoint Linux Team 
1190ede1e6f8SHighPoint Linux Team 	hptiop_shutdown(pcidev);
1191ede1e6f8SHighPoint Linux Team 
1192ede1e6f8SHighPoint Linux Team 	free_irq(hba->pcidev->irq, hba);
1193ede1e6f8SHighPoint Linux Team 
1194ede1e6f8SHighPoint Linux Team 	dma_free_coherent(&hba->pcidev->dev,
1195ede1e6f8SHighPoint Linux Team 			hba->req_size * hba->max_requests + 0x20,
1196ede1e6f8SHighPoint Linux Team 			hba->dma_coherent,
1197ede1e6f8SHighPoint Linux Team 			hba->dma_coherent_handle);
1198ede1e6f8SHighPoint Linux Team 
119900f59701SHighPoint Linux Team 	if (hba->ops->internal_memfree)
120000f59701SHighPoint Linux Team 		hba->ops->internal_memfree(hba);
120100f59701SHighPoint Linux Team 
120200f59701SHighPoint Linux Team 	hba->ops->unmap_pci_bar(hba);
1203ede1e6f8SHighPoint Linux Team 
1204ede1e6f8SHighPoint Linux Team 	pci_release_regions(hba->pcidev);
1205ede1e6f8SHighPoint Linux Team 	pci_set_drvdata(hba->pcidev, NULL);
1206ede1e6f8SHighPoint Linux Team 	pci_disable_device(hba->pcidev);
1207ede1e6f8SHighPoint Linux Team 
1208ede1e6f8SHighPoint Linux Team 	scsi_host_put(host);
1209ede1e6f8SHighPoint Linux Team }
1210ede1e6f8SHighPoint Linux Team 
121100f59701SHighPoint Linux Team static struct hptiop_adapter_ops hptiop_itl_ops = {
121200f59701SHighPoint Linux Team 	.iop_wait_ready    = iop_wait_ready_itl,
12139bcf0910SHarvey Harrison 	.internal_memalloc = NULL,
12149bcf0910SHarvey Harrison 	.internal_memfree  = NULL,
121500f59701SHighPoint Linux Team 	.map_pci_bar       = hptiop_map_pci_bar_itl,
121600f59701SHighPoint Linux Team 	.unmap_pci_bar     = hptiop_unmap_pci_bar_itl,
121700f59701SHighPoint Linux Team 	.enable_intr       = hptiop_enable_intr_itl,
121800f59701SHighPoint Linux Team 	.disable_intr      = hptiop_disable_intr_itl,
121900f59701SHighPoint Linux Team 	.get_config        = iop_get_config_itl,
122000f59701SHighPoint Linux Team 	.set_config        = iop_set_config_itl,
122100f59701SHighPoint Linux Team 	.iop_intr          = iop_intr_itl,
122200f59701SHighPoint Linux Team 	.post_msg          = hptiop_post_msg_itl,
122300f59701SHighPoint Linux Team 	.post_req          = hptiop_post_req_itl,
122400f59701SHighPoint Linux Team };
122500f59701SHighPoint Linux Team 
122600f59701SHighPoint Linux Team static struct hptiop_adapter_ops hptiop_mv_ops = {
122700f59701SHighPoint Linux Team 	.iop_wait_ready    = iop_wait_ready_mv,
122800f59701SHighPoint Linux Team 	.internal_memalloc = hptiop_internal_memalloc_mv,
122900f59701SHighPoint Linux Team 	.internal_memfree  = hptiop_internal_memfree_mv,
123000f59701SHighPoint Linux Team 	.map_pci_bar       = hptiop_map_pci_bar_mv,
123100f59701SHighPoint Linux Team 	.unmap_pci_bar     = hptiop_unmap_pci_bar_mv,
123200f59701SHighPoint Linux Team 	.enable_intr       = hptiop_enable_intr_mv,
123300f59701SHighPoint Linux Team 	.disable_intr      = hptiop_disable_intr_mv,
123400f59701SHighPoint Linux Team 	.get_config        = iop_get_config_mv,
123500f59701SHighPoint Linux Team 	.set_config        = iop_set_config_mv,
123600f59701SHighPoint Linux Team 	.iop_intr          = iop_intr_mv,
123700f59701SHighPoint Linux Team 	.post_msg          = hptiop_post_msg_mv,
123800f59701SHighPoint Linux Team 	.post_req          = hptiop_post_req_mv,
123900f59701SHighPoint Linux Team };
124000f59701SHighPoint Linux Team 
1241ede1e6f8SHighPoint Linux Team static struct pci_device_id hptiop_id_table[] = {
124200f59701SHighPoint Linux Team 	{ PCI_VDEVICE(TTI, 0x3220), (kernel_ulong_t)&hptiop_itl_ops },
124300f59701SHighPoint Linux Team 	{ PCI_VDEVICE(TTI, 0x3320), (kernel_ulong_t)&hptiop_itl_ops },
124400f59701SHighPoint Linux Team 	{ PCI_VDEVICE(TTI, 0x3520), (kernel_ulong_t)&hptiop_itl_ops },
124500f59701SHighPoint Linux Team 	{ PCI_VDEVICE(TTI, 0x4320), (kernel_ulong_t)&hptiop_itl_ops },
124600f59701SHighPoint Linux Team 	{ PCI_VDEVICE(TTI, 0x3510), (kernel_ulong_t)&hptiop_itl_ops },
124700f59701SHighPoint Linux Team 	{ PCI_VDEVICE(TTI, 0x3511), (kernel_ulong_t)&hptiop_itl_ops },
124800f59701SHighPoint Linux Team 	{ PCI_VDEVICE(TTI, 0x3521), (kernel_ulong_t)&hptiop_itl_ops },
124900f59701SHighPoint Linux Team 	{ PCI_VDEVICE(TTI, 0x3522), (kernel_ulong_t)&hptiop_itl_ops },
125000f59701SHighPoint Linux Team 	{ PCI_VDEVICE(TTI, 0x3410), (kernel_ulong_t)&hptiop_itl_ops },
125100f59701SHighPoint Linux Team 	{ PCI_VDEVICE(TTI, 0x3540), (kernel_ulong_t)&hptiop_itl_ops },
125200f59701SHighPoint Linux Team 	{ PCI_VDEVICE(TTI, 0x3120), (kernel_ulong_t)&hptiop_mv_ops },
125300f59701SHighPoint Linux Team 	{ PCI_VDEVICE(TTI, 0x3122), (kernel_ulong_t)&hptiop_mv_ops },
125400f59701SHighPoint Linux Team 	{ PCI_VDEVICE(TTI, 0x3020), (kernel_ulong_t)&hptiop_mv_ops },
1255ede1e6f8SHighPoint Linux Team 	{},
1256ede1e6f8SHighPoint Linux Team };
1257ede1e6f8SHighPoint Linux Team 
1258ede1e6f8SHighPoint Linux Team MODULE_DEVICE_TABLE(pci, hptiop_id_table);
1259ede1e6f8SHighPoint Linux Team 
1260ede1e6f8SHighPoint Linux Team static struct pci_driver hptiop_pci_driver = {
1261ede1e6f8SHighPoint Linux Team 	.name       = driver_name,
1262ede1e6f8SHighPoint Linux Team 	.id_table   = hptiop_id_table,
1263ede1e6f8SHighPoint Linux Team 	.probe      = hptiop_probe,
1264ede1e6f8SHighPoint Linux Team 	.remove     = hptiop_remove,
1265ede1e6f8SHighPoint Linux Team 	.shutdown   = hptiop_shutdown,
1266ede1e6f8SHighPoint Linux Team };
1267ede1e6f8SHighPoint Linux Team 
1268ede1e6f8SHighPoint Linux Team static int __init hptiop_module_init(void)
1269ede1e6f8SHighPoint Linux Team {
1270ede1e6f8SHighPoint Linux Team 	printk(KERN_INFO "%s %s\n", driver_name_long, driver_ver);
12713e74051bSChristoph Hellwig 	return pci_register_driver(&hptiop_pci_driver);
1272ede1e6f8SHighPoint Linux Team }
1273ede1e6f8SHighPoint Linux Team 
1274ede1e6f8SHighPoint Linux Team static void __exit hptiop_module_exit(void)
1275ede1e6f8SHighPoint Linux Team {
1276ede1e6f8SHighPoint Linux Team 	pci_unregister_driver(&hptiop_pci_driver);
1277ede1e6f8SHighPoint Linux Team }
1278ede1e6f8SHighPoint Linux Team 
1279ede1e6f8SHighPoint Linux Team 
1280ede1e6f8SHighPoint Linux Team module_init(hptiop_module_init);
1281ede1e6f8SHighPoint Linux Team module_exit(hptiop_module_exit);
1282ede1e6f8SHighPoint Linux Team 
1283ede1e6f8SHighPoint Linux Team MODULE_LICENSE("GPL");
1284db9b6e89SHighPoint Linux Team 
1285