18e8e69d6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ede1e6f8SHighPoint Linux Team /*
300f59701SHighPoint Linux Team * HighPoint RR3xxx/4xxx controller driver for Linux
4a93429c3Slinux * Copyright (C) 2006-2015 HighPoint Technologies, Inc. All Rights Reserved.
5ede1e6f8SHighPoint Linux Team *
6ede1e6f8SHighPoint Linux Team * Please report bugs/comments/suggestions to linux@highpoint-tech.com
7ede1e6f8SHighPoint Linux Team *
8ede1e6f8SHighPoint Linux Team * For more information, visit http://www.highpoint-tech.com
9ede1e6f8SHighPoint Linux Team */
10ede1e6f8SHighPoint Linux Team #include <linux/module.h>
11ede1e6f8SHighPoint Linux Team #include <linux/types.h>
12ede1e6f8SHighPoint Linux Team #include <linux/string.h>
13ede1e6f8SHighPoint Linux Team #include <linux/kernel.h>
14ede1e6f8SHighPoint Linux Team #include <linux/pci.h>
15ede1e6f8SHighPoint Linux Team #include <linux/interrupt.h>
16ede1e6f8SHighPoint Linux Team #include <linux/errno.h>
17ede1e6f8SHighPoint Linux Team #include <linux/delay.h>
18ede1e6f8SHighPoint Linux Team #include <linux/timer.h>
19ede1e6f8SHighPoint Linux Team #include <linux/spinlock.h>
205a0e3ad6STejun Heo #include <linux/gfp.h>
217c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
22ede1e6f8SHighPoint Linux Team #include <asm/io.h>
23ede1e6f8SHighPoint Linux Team #include <asm/div64.h>
24ede1e6f8SHighPoint Linux Team #include <scsi/scsi_cmnd.h>
25ede1e6f8SHighPoint Linux Team #include <scsi/scsi_device.h>
26ede1e6f8SHighPoint Linux Team #include <scsi/scsi.h>
27ede1e6f8SHighPoint Linux Team #include <scsi/scsi_tcq.h>
28ede1e6f8SHighPoint Linux Team #include <scsi/scsi_host.h>
29ede1e6f8SHighPoint Linux Team
30ede1e6f8SHighPoint Linux Team #include "hptiop.h"
31ede1e6f8SHighPoint Linux Team
32ede1e6f8SHighPoint Linux Team MODULE_AUTHOR("HighPoint Technologies, Inc.");
3300f59701SHighPoint Linux Team MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx/4xxx Controller Driver");
34ede1e6f8SHighPoint Linux Team
35ede1e6f8SHighPoint Linux Team static char driver_name[] = "hptiop";
3600f59701SHighPoint Linux Team static const char driver_name_long[] = "RocketRAID 3xxx/4xxx Controller driver";
37a93429c3Slinux static const char driver_ver[] = "v1.10.0";
38ede1e6f8SHighPoint Linux Team
3900f59701SHighPoint Linux Team static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec);
4000f59701SHighPoint Linux Team static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
4100f59701SHighPoint Linux Team struct hpt_iop_request_scsi_command *req);
4200f59701SHighPoint Linux Team static void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 tag);
4300f59701SHighPoint Linux Team static void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag);
44ede1e6f8SHighPoint Linux Team static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg);
45ede1e6f8SHighPoint Linux Team
iop_wait_ready_itl(struct hptiop_hba * hba,u32 millisec)4600f59701SHighPoint Linux Team static int iop_wait_ready_itl(struct hptiop_hba *hba, u32 millisec)
47ede1e6f8SHighPoint Linux Team {
48ede1e6f8SHighPoint Linux Team u32 req = 0;
49ede1e6f8SHighPoint Linux Team int i;
50ede1e6f8SHighPoint Linux Team
51ede1e6f8SHighPoint Linux Team for (i = 0; i < millisec; i++) {
5200f59701SHighPoint Linux Team req = readl(&hba->u.itl.iop->inbound_queue);
53ede1e6f8SHighPoint Linux Team if (req != IOPMU_QUEUE_EMPTY)
54ede1e6f8SHighPoint Linux Team break;
55ede1e6f8SHighPoint Linux Team msleep(1);
56ede1e6f8SHighPoint Linux Team }
57ede1e6f8SHighPoint Linux Team
58ede1e6f8SHighPoint Linux Team if (req != IOPMU_QUEUE_EMPTY) {
5900f59701SHighPoint Linux Team writel(req, &hba->u.itl.iop->outbound_queue);
6000f59701SHighPoint Linux Team readl(&hba->u.itl.iop->outbound_intstatus);
61ede1e6f8SHighPoint Linux Team return 0;
62ede1e6f8SHighPoint Linux Team }
63ede1e6f8SHighPoint Linux Team
64ede1e6f8SHighPoint Linux Team return -1;
65ede1e6f8SHighPoint Linux Team }
66ede1e6f8SHighPoint Linux Team
iop_wait_ready_mv(struct hptiop_hba * hba,u32 millisec)6700f59701SHighPoint Linux Team static int iop_wait_ready_mv(struct hptiop_hba *hba, u32 millisec)
68ede1e6f8SHighPoint Linux Team {
6900f59701SHighPoint Linux Team return iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_NOP, millisec);
70ede1e6f8SHighPoint Linux Team }
71ede1e6f8SHighPoint Linux Team
iop_wait_ready_mvfrey(struct hptiop_hba * hba,u32 millisec)72286aa031SHighPoint Linux Team static int iop_wait_ready_mvfrey(struct hptiop_hba *hba, u32 millisec)
73286aa031SHighPoint Linux Team {
74286aa031SHighPoint Linux Team return iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_NOP, millisec);
75286aa031SHighPoint Linux Team }
76286aa031SHighPoint Linux Team
hptiop_request_callback_itl(struct hptiop_hba * hba,u32 tag)7700f59701SHighPoint Linux Team static void hptiop_request_callback_itl(struct hptiop_hba *hba, u32 tag)
7800f59701SHighPoint Linux Team {
7900f59701SHighPoint Linux Team if (tag & IOPMU_QUEUE_ADDR_HOST_BIT)
8000f59701SHighPoint Linux Team hptiop_host_request_callback_itl(hba,
8100f59701SHighPoint Linux Team tag & ~IOPMU_QUEUE_ADDR_HOST_BIT);
8200f59701SHighPoint Linux Team else
8300f59701SHighPoint Linux Team hptiop_iop_request_callback_itl(hba, tag);
8400f59701SHighPoint Linux Team }
8500f59701SHighPoint Linux Team
hptiop_drain_outbound_queue_itl(struct hptiop_hba * hba)8600f59701SHighPoint Linux Team static void hptiop_drain_outbound_queue_itl(struct hptiop_hba *hba)
87ede1e6f8SHighPoint Linux Team {
88ede1e6f8SHighPoint Linux Team u32 req;
89ede1e6f8SHighPoint Linux Team
9000f59701SHighPoint Linux Team while ((req = readl(&hba->u.itl.iop->outbound_queue)) !=
9100f59701SHighPoint Linux Team IOPMU_QUEUE_EMPTY) {
92ede1e6f8SHighPoint Linux Team
93ede1e6f8SHighPoint Linux Team if (req & IOPMU_QUEUE_MASK_HOST_BITS)
9400f59701SHighPoint Linux Team hptiop_request_callback_itl(hba, req);
95ede1e6f8SHighPoint Linux Team else {
96ede1e6f8SHighPoint Linux Team struct hpt_iop_request_header __iomem * p;
97ede1e6f8SHighPoint Linux Team
98ede1e6f8SHighPoint Linux Team p = (struct hpt_iop_request_header __iomem *)
9900f59701SHighPoint Linux Team ((char __iomem *)hba->u.itl.iop + req);
100ede1e6f8SHighPoint Linux Team
101ede1e6f8SHighPoint Linux Team if (readl(&p->flags) & IOP_REQUEST_FLAG_SYNC_REQUEST) {
102ede1e6f8SHighPoint Linux Team if (readl(&p->context))
10300f59701SHighPoint Linux Team hptiop_request_callback_itl(hba, req);
104ede1e6f8SHighPoint Linux Team else
105ede1e6f8SHighPoint Linux Team writel(1, &p->context);
106ede1e6f8SHighPoint Linux Team }
107ede1e6f8SHighPoint Linux Team else
10800f59701SHighPoint Linux Team hptiop_request_callback_itl(hba, req);
109ede1e6f8SHighPoint Linux Team }
110ede1e6f8SHighPoint Linux Team }
111ede1e6f8SHighPoint Linux Team }
112ede1e6f8SHighPoint Linux Team
iop_intr_itl(struct hptiop_hba * hba)11300f59701SHighPoint Linux Team static int iop_intr_itl(struct hptiop_hba *hba)
114ede1e6f8SHighPoint Linux Team {
11500f59701SHighPoint Linux Team struct hpt_iopmu_itl __iomem *iop = hba->u.itl.iop;
1163bfc13c2SHighPoint Linux Team void __iomem *plx = hba->u.itl.plx;
117ede1e6f8SHighPoint Linux Team u32 status;
118ede1e6f8SHighPoint Linux Team int ret = 0;
119ede1e6f8SHighPoint Linux Team
1203bfc13c2SHighPoint Linux Team if (plx && readl(plx + 0x11C5C) & 0xf)
1213bfc13c2SHighPoint Linux Team writel(1, plx + 0x11C60);
1223bfc13c2SHighPoint Linux Team
123ede1e6f8SHighPoint Linux Team status = readl(&iop->outbound_intstatus);
124ede1e6f8SHighPoint Linux Team
125ede1e6f8SHighPoint Linux Team if (status & IOPMU_OUTBOUND_INT_MSG0) {
126ede1e6f8SHighPoint Linux Team u32 msg = readl(&iop->outbound_msgaddr0);
12700f59701SHighPoint Linux Team
128ede1e6f8SHighPoint Linux Team dprintk("received outbound msg %x\n", msg);
129ede1e6f8SHighPoint Linux Team writel(IOPMU_OUTBOUND_INT_MSG0, &iop->outbound_intstatus);
130ede1e6f8SHighPoint Linux Team hptiop_message_callback(hba, msg);
131ede1e6f8SHighPoint Linux Team ret = 1;
132ede1e6f8SHighPoint Linux Team }
133ede1e6f8SHighPoint Linux Team
134ede1e6f8SHighPoint Linux Team if (status & IOPMU_OUTBOUND_INT_POSTQUEUE) {
13500f59701SHighPoint Linux Team hptiop_drain_outbound_queue_itl(hba);
136ede1e6f8SHighPoint Linux Team ret = 1;
137ede1e6f8SHighPoint Linux Team }
138ede1e6f8SHighPoint Linux Team
139ede1e6f8SHighPoint Linux Team return ret;
140ede1e6f8SHighPoint Linux Team }
141ede1e6f8SHighPoint Linux Team
mv_outbound_read(struct hpt_iopmu_mv __iomem * mu)14200f59701SHighPoint Linux Team static u64 mv_outbound_read(struct hpt_iopmu_mv __iomem *mu)
14300f59701SHighPoint Linux Team {
14400f59701SHighPoint Linux Team u32 outbound_tail = readl(&mu->outbound_tail);
14500f59701SHighPoint Linux Team u32 outbound_head = readl(&mu->outbound_head);
14600f59701SHighPoint Linux Team
14700f59701SHighPoint Linux Team if (outbound_tail != outbound_head) {
14800f59701SHighPoint Linux Team u64 p;
14900f59701SHighPoint Linux Team
15000f59701SHighPoint Linux Team memcpy_fromio(&p, &mu->outbound_q[mu->outbound_tail], 8);
15100f59701SHighPoint Linux Team outbound_tail++;
15200f59701SHighPoint Linux Team
15300f59701SHighPoint Linux Team if (outbound_tail == MVIOP_QUEUE_LEN)
15400f59701SHighPoint Linux Team outbound_tail = 0;
15500f59701SHighPoint Linux Team writel(outbound_tail, &mu->outbound_tail);
15600f59701SHighPoint Linux Team return p;
15700f59701SHighPoint Linux Team } else
15800f59701SHighPoint Linux Team return 0;
15900f59701SHighPoint Linux Team }
16000f59701SHighPoint Linux Team
mv_inbound_write(u64 p,struct hptiop_hba * hba)16100f59701SHighPoint Linux Team static void mv_inbound_write(u64 p, struct hptiop_hba *hba)
16200f59701SHighPoint Linux Team {
16300f59701SHighPoint Linux Team u32 inbound_head = readl(&hba->u.mv.mu->inbound_head);
16400f59701SHighPoint Linux Team u32 head = inbound_head + 1;
16500f59701SHighPoint Linux Team
16600f59701SHighPoint Linux Team if (head == MVIOP_QUEUE_LEN)
16700f59701SHighPoint Linux Team head = 0;
16800f59701SHighPoint Linux Team
16900f59701SHighPoint Linux Team memcpy_toio(&hba->u.mv.mu->inbound_q[inbound_head], &p, 8);
17000f59701SHighPoint Linux Team writel(head, &hba->u.mv.mu->inbound_head);
17100f59701SHighPoint Linux Team writel(MVIOP_MU_INBOUND_INT_POSTQUEUE,
17200f59701SHighPoint Linux Team &hba->u.mv.regs->inbound_doorbell);
17300f59701SHighPoint Linux Team }
17400f59701SHighPoint Linux Team
hptiop_request_callback_mv(struct hptiop_hba * hba,u64 tag)17500f59701SHighPoint Linux Team static void hptiop_request_callback_mv(struct hptiop_hba *hba, u64 tag)
17600f59701SHighPoint Linux Team {
17700f59701SHighPoint Linux Team u32 req_type = (tag >> 5) & 0x7;
17800f59701SHighPoint Linux Team struct hpt_iop_request_scsi_command *req;
17900f59701SHighPoint Linux Team
18000f59701SHighPoint Linux Team dprintk("hptiop_request_callback_mv: tag=%llx\n", tag);
18100f59701SHighPoint Linux Team
18200f59701SHighPoint Linux Team BUG_ON((tag & MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT) == 0);
18300f59701SHighPoint Linux Team
18400f59701SHighPoint Linux Team switch (req_type) {
18500f59701SHighPoint Linux Team case IOP_REQUEST_TYPE_GET_CONFIG:
18600f59701SHighPoint Linux Team case IOP_REQUEST_TYPE_SET_CONFIG:
18700f59701SHighPoint Linux Team hba->msg_done = 1;
18800f59701SHighPoint Linux Team break;
18900f59701SHighPoint Linux Team
19000f59701SHighPoint Linux Team case IOP_REQUEST_TYPE_SCSI_COMMAND:
19100f59701SHighPoint Linux Team req = hba->reqs[tag >> 8].req_virt;
19200f59701SHighPoint Linux Team if (likely(tag & MVIOP_MU_QUEUE_REQUEST_RESULT_BIT))
19300f59701SHighPoint Linux Team req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS);
19400f59701SHighPoint Linux Team
19500f59701SHighPoint Linux Team hptiop_finish_scsi_req(hba, tag>>8, req);
19600f59701SHighPoint Linux Team break;
19700f59701SHighPoint Linux Team
19800f59701SHighPoint Linux Team default:
19900f59701SHighPoint Linux Team break;
20000f59701SHighPoint Linux Team }
20100f59701SHighPoint Linux Team }
20200f59701SHighPoint Linux Team
iop_intr_mv(struct hptiop_hba * hba)20300f59701SHighPoint Linux Team static int iop_intr_mv(struct hptiop_hba *hba)
20400f59701SHighPoint Linux Team {
20500f59701SHighPoint Linux Team u32 status;
20600f59701SHighPoint Linux Team int ret = 0;
20700f59701SHighPoint Linux Team
20800f59701SHighPoint Linux Team status = readl(&hba->u.mv.regs->outbound_doorbell);
20900f59701SHighPoint Linux Team writel(~status, &hba->u.mv.regs->outbound_doorbell);
21000f59701SHighPoint Linux Team
21100f59701SHighPoint Linux Team if (status & MVIOP_MU_OUTBOUND_INT_MSG) {
21200f59701SHighPoint Linux Team u32 msg;
21300f59701SHighPoint Linux Team msg = readl(&hba->u.mv.mu->outbound_msg);
21400f59701SHighPoint Linux Team dprintk("received outbound msg %x\n", msg);
21500f59701SHighPoint Linux Team hptiop_message_callback(hba, msg);
21600f59701SHighPoint Linux Team ret = 1;
21700f59701SHighPoint Linux Team }
21800f59701SHighPoint Linux Team
21900f59701SHighPoint Linux Team if (status & MVIOP_MU_OUTBOUND_INT_POSTQUEUE) {
22000f59701SHighPoint Linux Team u64 tag;
22100f59701SHighPoint Linux Team
22200f59701SHighPoint Linux Team while ((tag = mv_outbound_read(hba->u.mv.mu)))
22300f59701SHighPoint Linux Team hptiop_request_callback_mv(hba, tag);
22400f59701SHighPoint Linux Team ret = 1;
22500f59701SHighPoint Linux Team }
22600f59701SHighPoint Linux Team
22700f59701SHighPoint Linux Team return ret;
22800f59701SHighPoint Linux Team }
22900f59701SHighPoint Linux Team
hptiop_request_callback_mvfrey(struct hptiop_hba * hba,u32 _tag)230286aa031SHighPoint Linux Team static void hptiop_request_callback_mvfrey(struct hptiop_hba *hba, u32 _tag)
231286aa031SHighPoint Linux Team {
232286aa031SHighPoint Linux Team u32 req_type = _tag & 0xf;
233286aa031SHighPoint Linux Team struct hpt_iop_request_scsi_command *req;
234286aa031SHighPoint Linux Team
235286aa031SHighPoint Linux Team switch (req_type) {
236286aa031SHighPoint Linux Team case IOP_REQUEST_TYPE_GET_CONFIG:
237286aa031SHighPoint Linux Team case IOP_REQUEST_TYPE_SET_CONFIG:
238286aa031SHighPoint Linux Team hba->msg_done = 1;
239286aa031SHighPoint Linux Team break;
240286aa031SHighPoint Linux Team
241286aa031SHighPoint Linux Team case IOP_REQUEST_TYPE_SCSI_COMMAND:
242286aa031SHighPoint Linux Team req = hba->reqs[(_tag >> 4) & 0xff].req_virt;
243286aa031SHighPoint Linux Team if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT))
244286aa031SHighPoint Linux Team req->header.result = IOP_RESULT_SUCCESS;
245286aa031SHighPoint Linux Team hptiop_finish_scsi_req(hba, (_tag >> 4) & 0xff, req);
246286aa031SHighPoint Linux Team break;
247286aa031SHighPoint Linux Team
248286aa031SHighPoint Linux Team default:
249286aa031SHighPoint Linux Team break;
250286aa031SHighPoint Linux Team }
251286aa031SHighPoint Linux Team }
252286aa031SHighPoint Linux Team
iop_intr_mvfrey(struct hptiop_hba * hba)253286aa031SHighPoint Linux Team static int iop_intr_mvfrey(struct hptiop_hba *hba)
254286aa031SHighPoint Linux Team {
255286aa031SHighPoint Linux Team u32 _tag, status, cptr, cur_rptr;
256286aa031SHighPoint Linux Team int ret = 0;
257286aa031SHighPoint Linux Team
258286aa031SHighPoint Linux Team if (hba->initialized)
259286aa031SHighPoint Linux Team writel(0, &(hba->u.mvfrey.mu->pcie_f0_int_enable));
260286aa031SHighPoint Linux Team
261286aa031SHighPoint Linux Team status = readl(&(hba->u.mvfrey.mu->f0_doorbell));
262286aa031SHighPoint Linux Team if (status) {
263286aa031SHighPoint Linux Team writel(status, &(hba->u.mvfrey.mu->f0_doorbell));
264286aa031SHighPoint Linux Team if (status & CPU_TO_F0_DRBL_MSG_BIT) {
265286aa031SHighPoint Linux Team u32 msg = readl(&(hba->u.mvfrey.mu->cpu_to_f0_msg_a));
266286aa031SHighPoint Linux Team dprintk("received outbound msg %x\n", msg);
267286aa031SHighPoint Linux Team hptiop_message_callback(hba, msg);
268286aa031SHighPoint Linux Team }
269286aa031SHighPoint Linux Team ret = 1;
270286aa031SHighPoint Linux Team }
271286aa031SHighPoint Linux Team
272286aa031SHighPoint Linux Team status = readl(&(hba->u.mvfrey.mu->isr_cause));
273286aa031SHighPoint Linux Team if (status) {
274286aa031SHighPoint Linux Team writel(status, &(hba->u.mvfrey.mu->isr_cause));
275286aa031SHighPoint Linux Team do {
276286aa031SHighPoint Linux Team cptr = *hba->u.mvfrey.outlist_cptr & 0xff;
277286aa031SHighPoint Linux Team cur_rptr = hba->u.mvfrey.outlist_rptr;
278286aa031SHighPoint Linux Team while (cur_rptr != cptr) {
279286aa031SHighPoint Linux Team cur_rptr++;
280286aa031SHighPoint Linux Team if (cur_rptr == hba->u.mvfrey.list_count)
281286aa031SHighPoint Linux Team cur_rptr = 0;
282286aa031SHighPoint Linux Team
283286aa031SHighPoint Linux Team _tag = hba->u.mvfrey.outlist[cur_rptr].val;
284286aa031SHighPoint Linux Team BUG_ON(!(_tag & IOPMU_QUEUE_MASK_HOST_BITS));
285286aa031SHighPoint Linux Team hptiop_request_callback_mvfrey(hba, _tag);
286286aa031SHighPoint Linux Team ret = 1;
287286aa031SHighPoint Linux Team }
288286aa031SHighPoint Linux Team hba->u.mvfrey.outlist_rptr = cur_rptr;
289286aa031SHighPoint Linux Team } while (cptr != (*hba->u.mvfrey.outlist_cptr & 0xff));
290286aa031SHighPoint Linux Team }
291286aa031SHighPoint Linux Team
292286aa031SHighPoint Linux Team if (hba->initialized)
293286aa031SHighPoint Linux Team writel(0x1010, &(hba->u.mvfrey.mu->pcie_f0_int_enable));
294286aa031SHighPoint Linux Team
295286aa031SHighPoint Linux Team return ret;
296286aa031SHighPoint Linux Team }
297286aa031SHighPoint Linux Team
iop_send_sync_request_itl(struct hptiop_hba * hba,void __iomem * _req,u32 millisec)29800f59701SHighPoint Linux Team static int iop_send_sync_request_itl(struct hptiop_hba *hba,
299ede1e6f8SHighPoint Linux Team void __iomem *_req, u32 millisec)
300ede1e6f8SHighPoint Linux Team {
301ede1e6f8SHighPoint Linux Team struct hpt_iop_request_header __iomem *req = _req;
302ede1e6f8SHighPoint Linux Team u32 i;
303ede1e6f8SHighPoint Linux Team
30400f59701SHighPoint Linux Team writel(readl(&req->flags) | IOP_REQUEST_FLAG_SYNC_REQUEST, &req->flags);
305ede1e6f8SHighPoint Linux Team writel(0, &req->context);
30600f59701SHighPoint Linux Team writel((unsigned long)req - (unsigned long)hba->u.itl.iop,
30700f59701SHighPoint Linux Team &hba->u.itl.iop->inbound_queue);
30800f59701SHighPoint Linux Team readl(&hba->u.itl.iop->outbound_intstatus);
309ede1e6f8SHighPoint Linux Team
310ede1e6f8SHighPoint Linux Team for (i = 0; i < millisec; i++) {
31100f59701SHighPoint Linux Team iop_intr_itl(hba);
312ede1e6f8SHighPoint Linux Team if (readl(&req->context))
313ede1e6f8SHighPoint Linux Team return 0;
314ede1e6f8SHighPoint Linux Team msleep(1);
315ede1e6f8SHighPoint Linux Team }
316ede1e6f8SHighPoint Linux Team
317ede1e6f8SHighPoint Linux Team return -1;
318ede1e6f8SHighPoint Linux Team }
319ede1e6f8SHighPoint Linux Team
iop_send_sync_request_mv(struct hptiop_hba * hba,u32 size_bits,u32 millisec)32000f59701SHighPoint Linux Team static int iop_send_sync_request_mv(struct hptiop_hba *hba,
32100f59701SHighPoint Linux Team u32 size_bits, u32 millisec)
32200f59701SHighPoint Linux Team {
32300f59701SHighPoint Linux Team struct hpt_iop_request_header *reqhdr = hba->u.mv.internal_req;
32400f59701SHighPoint Linux Team u32 i;
32500f59701SHighPoint Linux Team
32600f59701SHighPoint Linux Team hba->msg_done = 0;
32700f59701SHighPoint Linux Team reqhdr->flags |= cpu_to_le32(IOP_REQUEST_FLAG_SYNC_REQUEST);
32800f59701SHighPoint Linux Team mv_inbound_write(hba->u.mv.internal_req_phy |
32900f59701SHighPoint Linux Team MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bits, hba);
33000f59701SHighPoint Linux Team
33100f59701SHighPoint Linux Team for (i = 0; i < millisec; i++) {
33200f59701SHighPoint Linux Team iop_intr_mv(hba);
33300f59701SHighPoint Linux Team if (hba->msg_done)
33400f59701SHighPoint Linux Team return 0;
33500f59701SHighPoint Linux Team msleep(1);
33600f59701SHighPoint Linux Team }
33700f59701SHighPoint Linux Team return -1;
33800f59701SHighPoint Linux Team }
33900f59701SHighPoint Linux Team
iop_send_sync_request_mvfrey(struct hptiop_hba * hba,u32 size_bits,u32 millisec)340286aa031SHighPoint Linux Team static int iop_send_sync_request_mvfrey(struct hptiop_hba *hba,
341286aa031SHighPoint Linux Team u32 size_bits, u32 millisec)
342286aa031SHighPoint Linux Team {
343286aa031SHighPoint Linux Team struct hpt_iop_request_header *reqhdr =
344286aa031SHighPoint Linux Team hba->u.mvfrey.internal_req.req_virt;
345286aa031SHighPoint Linux Team u32 i;
346286aa031SHighPoint Linux Team
347286aa031SHighPoint Linux Team hba->msg_done = 0;
348286aa031SHighPoint Linux Team reqhdr->flags |= cpu_to_le32(IOP_REQUEST_FLAG_SYNC_REQUEST);
349286aa031SHighPoint Linux Team hba->ops->post_req(hba, &(hba->u.mvfrey.internal_req));
350286aa031SHighPoint Linux Team
351286aa031SHighPoint Linux Team for (i = 0; i < millisec; i++) {
352286aa031SHighPoint Linux Team iop_intr_mvfrey(hba);
353286aa031SHighPoint Linux Team if (hba->msg_done)
354286aa031SHighPoint Linux Team break;
355286aa031SHighPoint Linux Team msleep(1);
356286aa031SHighPoint Linux Team }
357286aa031SHighPoint Linux Team return hba->msg_done ? 0 : -1;
358286aa031SHighPoint Linux Team }
359286aa031SHighPoint Linux Team
hptiop_post_msg_itl(struct hptiop_hba * hba,u32 msg)36000f59701SHighPoint Linux Team static void hptiop_post_msg_itl(struct hptiop_hba *hba, u32 msg)
36100f59701SHighPoint Linux Team {
36200f59701SHighPoint Linux Team writel(msg, &hba->u.itl.iop->inbound_msgaddr0);
36300f59701SHighPoint Linux Team readl(&hba->u.itl.iop->outbound_intstatus);
36400f59701SHighPoint Linux Team }
36500f59701SHighPoint Linux Team
hptiop_post_msg_mv(struct hptiop_hba * hba,u32 msg)36600f59701SHighPoint Linux Team static void hptiop_post_msg_mv(struct hptiop_hba *hba, u32 msg)
36700f59701SHighPoint Linux Team {
36800f59701SHighPoint Linux Team writel(msg, &hba->u.mv.mu->inbound_msg);
36900f59701SHighPoint Linux Team writel(MVIOP_MU_INBOUND_INT_MSG, &hba->u.mv.regs->inbound_doorbell);
37000f59701SHighPoint Linux Team readl(&hba->u.mv.regs->inbound_doorbell);
37100f59701SHighPoint Linux Team }
37200f59701SHighPoint Linux Team
hptiop_post_msg_mvfrey(struct hptiop_hba * hba,u32 msg)373286aa031SHighPoint Linux Team static void hptiop_post_msg_mvfrey(struct hptiop_hba *hba, u32 msg)
374286aa031SHighPoint Linux Team {
375286aa031SHighPoint Linux Team writel(msg, &(hba->u.mvfrey.mu->f0_to_cpu_msg_a));
376286aa031SHighPoint Linux Team readl(&(hba->u.mvfrey.mu->f0_to_cpu_msg_a));
377286aa031SHighPoint Linux Team }
378286aa031SHighPoint Linux Team
iop_send_sync_msg(struct hptiop_hba * hba,u32 msg,u32 millisec)379ede1e6f8SHighPoint Linux Team static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec)
380ede1e6f8SHighPoint Linux Team {
381ede1e6f8SHighPoint Linux Team u32 i;
382ede1e6f8SHighPoint Linux Team
383ede1e6f8SHighPoint Linux Team hba->msg_done = 0;
384286aa031SHighPoint Linux Team hba->ops->disable_intr(hba);
38500f59701SHighPoint Linux Team hba->ops->post_msg(hba, msg);
386ede1e6f8SHighPoint Linux Team
387ede1e6f8SHighPoint Linux Team for (i = 0; i < millisec; i++) {
388ede1e6f8SHighPoint Linux Team spin_lock_irq(hba->host->host_lock);
38900f59701SHighPoint Linux Team hba->ops->iop_intr(hba);
390ede1e6f8SHighPoint Linux Team spin_unlock_irq(hba->host->host_lock);
391ede1e6f8SHighPoint Linux Team if (hba->msg_done)
392ede1e6f8SHighPoint Linux Team break;
393ede1e6f8SHighPoint Linux Team msleep(1);
394ede1e6f8SHighPoint Linux Team }
395ede1e6f8SHighPoint Linux Team
396286aa031SHighPoint Linux Team hba->ops->enable_intr(hba);
397ede1e6f8SHighPoint Linux Team return hba->msg_done? 0 : -1;
398ede1e6f8SHighPoint Linux Team }
399ede1e6f8SHighPoint Linux Team
iop_get_config_itl(struct hptiop_hba * hba,struct hpt_iop_request_get_config * config)40000f59701SHighPoint Linux Team static int iop_get_config_itl(struct hptiop_hba *hba,
401ede1e6f8SHighPoint Linux Team struct hpt_iop_request_get_config *config)
402ede1e6f8SHighPoint Linux Team {
403ede1e6f8SHighPoint Linux Team u32 req32;
404ede1e6f8SHighPoint Linux Team struct hpt_iop_request_get_config __iomem *req;
405ede1e6f8SHighPoint Linux Team
40600f59701SHighPoint Linux Team req32 = readl(&hba->u.itl.iop->inbound_queue);
407ede1e6f8SHighPoint Linux Team if (req32 == IOPMU_QUEUE_EMPTY)
408ede1e6f8SHighPoint Linux Team return -1;
409ede1e6f8SHighPoint Linux Team
410ede1e6f8SHighPoint Linux Team req = (struct hpt_iop_request_get_config __iomem *)
41100f59701SHighPoint Linux Team ((unsigned long)hba->u.itl.iop + req32);
412ede1e6f8SHighPoint Linux Team
413ede1e6f8SHighPoint Linux Team writel(0, &req->header.flags);
414ede1e6f8SHighPoint Linux Team writel(IOP_REQUEST_TYPE_GET_CONFIG, &req->header.type);
415ede1e6f8SHighPoint Linux Team writel(sizeof(struct hpt_iop_request_get_config), &req->header.size);
416ede1e6f8SHighPoint Linux Team writel(IOP_RESULT_PENDING, &req->header.result);
417ede1e6f8SHighPoint Linux Team
41800f59701SHighPoint Linux Team if (iop_send_sync_request_itl(hba, req, 20000)) {
419ede1e6f8SHighPoint Linux Team dprintk("Get config send cmd failed\n");
420ede1e6f8SHighPoint Linux Team return -1;
421ede1e6f8SHighPoint Linux Team }
422ede1e6f8SHighPoint Linux Team
423ede1e6f8SHighPoint Linux Team memcpy_fromio(config, req, sizeof(*config));
42400f59701SHighPoint Linux Team writel(req32, &hba->u.itl.iop->outbound_queue);
425ede1e6f8SHighPoint Linux Team return 0;
426ede1e6f8SHighPoint Linux Team }
427ede1e6f8SHighPoint Linux Team
iop_get_config_mv(struct hptiop_hba * hba,struct hpt_iop_request_get_config * config)42800f59701SHighPoint Linux Team static int iop_get_config_mv(struct hptiop_hba *hba,
42900f59701SHighPoint Linux Team struct hpt_iop_request_get_config *config)
43000f59701SHighPoint Linux Team {
43100f59701SHighPoint Linux Team struct hpt_iop_request_get_config *req = hba->u.mv.internal_req;
43200f59701SHighPoint Linux Team
43300f59701SHighPoint Linux Team req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
43400f59701SHighPoint Linux Team req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_GET_CONFIG);
43500f59701SHighPoint Linux Team req->header.size =
43600f59701SHighPoint Linux Team cpu_to_le32(sizeof(struct hpt_iop_request_get_config));
43700f59701SHighPoint Linux Team req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
438f6b196a2SJames Bottomley req->header.context = cpu_to_le32(IOP_REQUEST_TYPE_GET_CONFIG<<5);
439f6b196a2SJames Bottomley req->header.context_hi32 = 0;
44000f59701SHighPoint Linux Team
44100f59701SHighPoint Linux Team if (iop_send_sync_request_mv(hba, 0, 20000)) {
44200f59701SHighPoint Linux Team dprintk("Get config send cmd failed\n");
44300f59701SHighPoint Linux Team return -1;
44400f59701SHighPoint Linux Team }
44500f59701SHighPoint Linux Team
44600f59701SHighPoint Linux Team memcpy(config, req, sizeof(struct hpt_iop_request_get_config));
44700f59701SHighPoint Linux Team return 0;
44800f59701SHighPoint Linux Team }
44900f59701SHighPoint Linux Team
iop_get_config_mvfrey(struct hptiop_hba * hba,struct hpt_iop_request_get_config * config)450286aa031SHighPoint Linux Team static int iop_get_config_mvfrey(struct hptiop_hba *hba,
451286aa031SHighPoint Linux Team struct hpt_iop_request_get_config *config)
452286aa031SHighPoint Linux Team {
453286aa031SHighPoint Linux Team struct hpt_iop_request_get_config *info = hba->u.mvfrey.config;
454286aa031SHighPoint Linux Team
455286aa031SHighPoint Linux Team if (info->header.size != sizeof(struct hpt_iop_request_get_config) ||
456286aa031SHighPoint Linux Team info->header.type != IOP_REQUEST_TYPE_GET_CONFIG)
457286aa031SHighPoint Linux Team return -1;
458286aa031SHighPoint Linux Team
459286aa031SHighPoint Linux Team config->interface_version = info->interface_version;
460286aa031SHighPoint Linux Team config->firmware_version = info->firmware_version;
461286aa031SHighPoint Linux Team config->max_requests = info->max_requests;
462286aa031SHighPoint Linux Team config->request_size = info->request_size;
463286aa031SHighPoint Linux Team config->max_sg_count = info->max_sg_count;
464286aa031SHighPoint Linux Team config->data_transfer_length = info->data_transfer_length;
465286aa031SHighPoint Linux Team config->alignment_mask = info->alignment_mask;
466286aa031SHighPoint Linux Team config->max_devices = info->max_devices;
467286aa031SHighPoint Linux Team config->sdram_size = info->sdram_size;
468286aa031SHighPoint Linux Team
469286aa031SHighPoint Linux Team return 0;
470286aa031SHighPoint Linux Team }
471286aa031SHighPoint Linux Team
iop_set_config_itl(struct hptiop_hba * hba,struct hpt_iop_request_set_config * config)47200f59701SHighPoint Linux Team static int iop_set_config_itl(struct hptiop_hba *hba,
473ede1e6f8SHighPoint Linux Team struct hpt_iop_request_set_config *config)
474ede1e6f8SHighPoint Linux Team {
475ede1e6f8SHighPoint Linux Team u32 req32;
476ede1e6f8SHighPoint Linux Team struct hpt_iop_request_set_config __iomem *req;
477ede1e6f8SHighPoint Linux Team
47800f59701SHighPoint Linux Team req32 = readl(&hba->u.itl.iop->inbound_queue);
479ede1e6f8SHighPoint Linux Team if (req32 == IOPMU_QUEUE_EMPTY)
480ede1e6f8SHighPoint Linux Team return -1;
481ede1e6f8SHighPoint Linux Team
482ede1e6f8SHighPoint Linux Team req = (struct hpt_iop_request_set_config __iomem *)
48300f59701SHighPoint Linux Team ((unsigned long)hba->u.itl.iop + req32);
484ede1e6f8SHighPoint Linux Team
485ede1e6f8SHighPoint Linux Team memcpy_toio((u8 __iomem *)req + sizeof(struct hpt_iop_request_header),
486ede1e6f8SHighPoint Linux Team (u8 *)config + sizeof(struct hpt_iop_request_header),
487ede1e6f8SHighPoint Linux Team sizeof(struct hpt_iop_request_set_config) -
488ede1e6f8SHighPoint Linux Team sizeof(struct hpt_iop_request_header));
489ede1e6f8SHighPoint Linux Team
490ede1e6f8SHighPoint Linux Team writel(0, &req->header.flags);
491ede1e6f8SHighPoint Linux Team writel(IOP_REQUEST_TYPE_SET_CONFIG, &req->header.type);
492ede1e6f8SHighPoint Linux Team writel(sizeof(struct hpt_iop_request_set_config), &req->header.size);
493ede1e6f8SHighPoint Linux Team writel(IOP_RESULT_PENDING, &req->header.result);
494ede1e6f8SHighPoint Linux Team
49500f59701SHighPoint Linux Team if (iop_send_sync_request_itl(hba, req, 20000)) {
496ede1e6f8SHighPoint Linux Team dprintk("Set config send cmd failed\n");
497ede1e6f8SHighPoint Linux Team return -1;
498ede1e6f8SHighPoint Linux Team }
499ede1e6f8SHighPoint Linux Team
50000f59701SHighPoint Linux Team writel(req32, &hba->u.itl.iop->outbound_queue);
501ede1e6f8SHighPoint Linux Team return 0;
502ede1e6f8SHighPoint Linux Team }
503ede1e6f8SHighPoint Linux Team
iop_set_config_mv(struct hptiop_hba * hba,struct hpt_iop_request_set_config * config)50400f59701SHighPoint Linux Team static int iop_set_config_mv(struct hptiop_hba *hba,
50500f59701SHighPoint Linux Team struct hpt_iop_request_set_config *config)
50600f59701SHighPoint Linux Team {
50700f59701SHighPoint Linux Team struct hpt_iop_request_set_config *req = hba->u.mv.internal_req;
50800f59701SHighPoint Linux Team
50900f59701SHighPoint Linux Team memcpy(req, config, sizeof(struct hpt_iop_request_set_config));
51000f59701SHighPoint Linux Team req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
51100f59701SHighPoint Linux Team req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG);
51200f59701SHighPoint Linux Team req->header.size =
51300f59701SHighPoint Linux Team cpu_to_le32(sizeof(struct hpt_iop_request_set_config));
51400f59701SHighPoint Linux Team req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
515f6b196a2SJames Bottomley req->header.context = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG<<5);
516f6b196a2SJames Bottomley req->header.context_hi32 = 0;
51700f59701SHighPoint Linux Team
51800f59701SHighPoint Linux Team if (iop_send_sync_request_mv(hba, 0, 20000)) {
51900f59701SHighPoint Linux Team dprintk("Set config send cmd failed\n");
52000f59701SHighPoint Linux Team return -1;
52100f59701SHighPoint Linux Team }
52200f59701SHighPoint Linux Team
52300f59701SHighPoint Linux Team return 0;
52400f59701SHighPoint Linux Team }
52500f59701SHighPoint Linux Team
iop_set_config_mvfrey(struct hptiop_hba * hba,struct hpt_iop_request_set_config * config)526286aa031SHighPoint Linux Team static int iop_set_config_mvfrey(struct hptiop_hba *hba,
527286aa031SHighPoint Linux Team struct hpt_iop_request_set_config *config)
528286aa031SHighPoint Linux Team {
529286aa031SHighPoint Linux Team struct hpt_iop_request_set_config *req =
530286aa031SHighPoint Linux Team hba->u.mvfrey.internal_req.req_virt;
531286aa031SHighPoint Linux Team
532286aa031SHighPoint Linux Team memcpy(req, config, sizeof(struct hpt_iop_request_set_config));
533286aa031SHighPoint Linux Team req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
534286aa031SHighPoint Linux Team req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG);
535286aa031SHighPoint Linux Team req->header.size =
536286aa031SHighPoint Linux Team cpu_to_le32(sizeof(struct hpt_iop_request_set_config));
537286aa031SHighPoint Linux Team req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
538286aa031SHighPoint Linux Team req->header.context = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG<<5);
539286aa031SHighPoint Linux Team req->header.context_hi32 = 0;
540286aa031SHighPoint Linux Team
541286aa031SHighPoint Linux Team if (iop_send_sync_request_mvfrey(hba, 0, 20000)) {
542286aa031SHighPoint Linux Team dprintk("Set config send cmd failed\n");
543286aa031SHighPoint Linux Team return -1;
544286aa031SHighPoint Linux Team }
545286aa031SHighPoint Linux Team
546286aa031SHighPoint Linux Team return 0;
547286aa031SHighPoint Linux Team }
548286aa031SHighPoint Linux Team
hptiop_enable_intr_itl(struct hptiop_hba * hba)54900f59701SHighPoint Linux Team static void hptiop_enable_intr_itl(struct hptiop_hba *hba)
55000f59701SHighPoint Linux Team {
55100f59701SHighPoint Linux Team writel(~(IOPMU_OUTBOUND_INT_POSTQUEUE | IOPMU_OUTBOUND_INT_MSG0),
55200f59701SHighPoint Linux Team &hba->u.itl.iop->outbound_intmask);
55300f59701SHighPoint Linux Team }
55400f59701SHighPoint Linux Team
hptiop_enable_intr_mv(struct hptiop_hba * hba)55500f59701SHighPoint Linux Team static void hptiop_enable_intr_mv(struct hptiop_hba *hba)
55600f59701SHighPoint Linux Team {
55700f59701SHighPoint Linux Team writel(MVIOP_MU_OUTBOUND_INT_POSTQUEUE | MVIOP_MU_OUTBOUND_INT_MSG,
55800f59701SHighPoint Linux Team &hba->u.mv.regs->outbound_intmask);
55900f59701SHighPoint Linux Team }
56000f59701SHighPoint Linux Team
hptiop_enable_intr_mvfrey(struct hptiop_hba * hba)561286aa031SHighPoint Linux Team static void hptiop_enable_intr_mvfrey(struct hptiop_hba *hba)
562286aa031SHighPoint Linux Team {
563286aa031SHighPoint Linux Team writel(CPU_TO_F0_DRBL_MSG_BIT, &(hba->u.mvfrey.mu->f0_doorbell_enable));
564286aa031SHighPoint Linux Team writel(0x1, &(hba->u.mvfrey.mu->isr_enable));
565286aa031SHighPoint Linux Team writel(0x1010, &(hba->u.mvfrey.mu->pcie_f0_int_enable));
566286aa031SHighPoint Linux Team }
567286aa031SHighPoint Linux Team
hptiop_initialize_iop(struct hptiop_hba * hba)568ede1e6f8SHighPoint Linux Team static int hptiop_initialize_iop(struct hptiop_hba *hba)
569ede1e6f8SHighPoint Linux Team {
570ede1e6f8SHighPoint Linux Team /* enable interrupts */
57100f59701SHighPoint Linux Team hba->ops->enable_intr(hba);
572ede1e6f8SHighPoint Linux Team
573ede1e6f8SHighPoint Linux Team hba->initialized = 1;
574ede1e6f8SHighPoint Linux Team
575ede1e6f8SHighPoint Linux Team /* start background tasks */
576ede1e6f8SHighPoint Linux Team if (iop_send_sync_msg(hba,
577ede1e6f8SHighPoint Linux Team IOPMU_INBOUND_MSG0_START_BACKGROUND_TASK, 5000)) {
578ede1e6f8SHighPoint Linux Team printk(KERN_ERR "scsi%d: fail to start background task\n",
579ede1e6f8SHighPoint Linux Team hba->host->host_no);
580ede1e6f8SHighPoint Linux Team return -1;
581ede1e6f8SHighPoint Linux Team }
582ede1e6f8SHighPoint Linux Team return 0;
583ede1e6f8SHighPoint Linux Team }
584ede1e6f8SHighPoint Linux Team
hptiop_map_pci_bar(struct hptiop_hba * hba,int index)58500f59701SHighPoint Linux Team static void __iomem *hptiop_map_pci_bar(struct hptiop_hba *hba, int index)
586ede1e6f8SHighPoint Linux Team {
587ede1e6f8SHighPoint Linux Team u32 mem_base_phy, length;
588ede1e6f8SHighPoint Linux Team void __iomem *mem_base_virt;
58900f59701SHighPoint Linux Team
590ede1e6f8SHighPoint Linux Team struct pci_dev *pcidev = hba->pcidev;
591ede1e6f8SHighPoint Linux Team
59200f59701SHighPoint Linux Team
59300f59701SHighPoint Linux Team if (!(pci_resource_flags(pcidev, index) & IORESOURCE_MEM)) {
594ede1e6f8SHighPoint Linux Team printk(KERN_ERR "scsi%d: pci resource invalid\n",
595ede1e6f8SHighPoint Linux Team hba->host->host_no);
5969bcf0910SHarvey Harrison return NULL;
597ede1e6f8SHighPoint Linux Team }
598ede1e6f8SHighPoint Linux Team
59900f59701SHighPoint Linux Team mem_base_phy = pci_resource_start(pcidev, index);
60000f59701SHighPoint Linux Team length = pci_resource_len(pcidev, index);
601ede1e6f8SHighPoint Linux Team mem_base_virt = ioremap(mem_base_phy, length);
602ede1e6f8SHighPoint Linux Team
603ede1e6f8SHighPoint Linux Team if (!mem_base_virt) {
604ede1e6f8SHighPoint Linux Team printk(KERN_ERR "scsi%d: Fail to ioremap memory space\n",
605ede1e6f8SHighPoint Linux Team hba->host->host_no);
6069bcf0910SHarvey Harrison return NULL;
60700f59701SHighPoint Linux Team }
60800f59701SHighPoint Linux Team return mem_base_virt;
60900f59701SHighPoint Linux Team }
61000f59701SHighPoint Linux Team
hptiop_map_pci_bar_itl(struct hptiop_hba * hba)61100f59701SHighPoint Linux Team static int hptiop_map_pci_bar_itl(struct hptiop_hba *hba)
61200f59701SHighPoint Linux Team {
6133bfc13c2SHighPoint Linux Team struct pci_dev *pcidev = hba->pcidev;
61400f59701SHighPoint Linux Team hba->u.itl.iop = hptiop_map_pci_bar(hba, 0);
6153bfc13c2SHighPoint Linux Team if (hba->u.itl.iop == NULL)
616ede1e6f8SHighPoint Linux Team return -1;
6173bfc13c2SHighPoint Linux Team if ((pcidev->device & 0xff00) == 0x4400) {
6183bfc13c2SHighPoint Linux Team hba->u.itl.plx = hba->u.itl.iop;
6193bfc13c2SHighPoint Linux Team hba->u.itl.iop = hptiop_map_pci_bar(hba, 2);
6203bfc13c2SHighPoint Linux Team if (hba->u.itl.iop == NULL) {
6213bfc13c2SHighPoint Linux Team iounmap(hba->u.itl.plx);
6223bfc13c2SHighPoint Linux Team return -1;
6233bfc13c2SHighPoint Linux Team }
6243bfc13c2SHighPoint Linux Team }
6253bfc13c2SHighPoint Linux Team return 0;
626ede1e6f8SHighPoint Linux Team }
627ede1e6f8SHighPoint Linux Team
hptiop_unmap_pci_bar_itl(struct hptiop_hba * hba)62800f59701SHighPoint Linux Team static void hptiop_unmap_pci_bar_itl(struct hptiop_hba *hba)
62900f59701SHighPoint Linux Team {
6303bfc13c2SHighPoint Linux Team if (hba->u.itl.plx)
6313bfc13c2SHighPoint Linux Team iounmap(hba->u.itl.plx);
63200f59701SHighPoint Linux Team iounmap(hba->u.itl.iop);
63300f59701SHighPoint Linux Team }
63400f59701SHighPoint Linux Team
hptiop_map_pci_bar_mv(struct hptiop_hba * hba)63500f59701SHighPoint Linux Team static int hptiop_map_pci_bar_mv(struct hptiop_hba *hba)
63600f59701SHighPoint Linux Team {
63700f59701SHighPoint Linux Team hba->u.mv.regs = hptiop_map_pci_bar(hba, 0);
6389bcf0910SHarvey Harrison if (hba->u.mv.regs == NULL)
63900f59701SHighPoint Linux Team return -1;
64000f59701SHighPoint Linux Team
64100f59701SHighPoint Linux Team hba->u.mv.mu = hptiop_map_pci_bar(hba, 2);
6429bcf0910SHarvey Harrison if (hba->u.mv.mu == NULL) {
64300f59701SHighPoint Linux Team iounmap(hba->u.mv.regs);
64400f59701SHighPoint Linux Team return -1;
64500f59701SHighPoint Linux Team }
64600f59701SHighPoint Linux Team
647ede1e6f8SHighPoint Linux Team return 0;
648ede1e6f8SHighPoint Linux Team }
649ede1e6f8SHighPoint Linux Team
hptiop_map_pci_bar_mvfrey(struct hptiop_hba * hba)650286aa031SHighPoint Linux Team static int hptiop_map_pci_bar_mvfrey(struct hptiop_hba *hba)
651286aa031SHighPoint Linux Team {
652286aa031SHighPoint Linux Team hba->u.mvfrey.config = hptiop_map_pci_bar(hba, 0);
653286aa031SHighPoint Linux Team if (hba->u.mvfrey.config == NULL)
654286aa031SHighPoint Linux Team return -1;
655286aa031SHighPoint Linux Team
656286aa031SHighPoint Linux Team hba->u.mvfrey.mu = hptiop_map_pci_bar(hba, 2);
657286aa031SHighPoint Linux Team if (hba->u.mvfrey.mu == NULL) {
658286aa031SHighPoint Linux Team iounmap(hba->u.mvfrey.config);
659286aa031SHighPoint Linux Team return -1;
660286aa031SHighPoint Linux Team }
661286aa031SHighPoint Linux Team
662286aa031SHighPoint Linux Team return 0;
663286aa031SHighPoint Linux Team }
664286aa031SHighPoint Linux Team
hptiop_unmap_pci_bar_mv(struct hptiop_hba * hba)66500f59701SHighPoint Linux Team static void hptiop_unmap_pci_bar_mv(struct hptiop_hba *hba)
66600f59701SHighPoint Linux Team {
66700f59701SHighPoint Linux Team iounmap(hba->u.mv.regs);
66800f59701SHighPoint Linux Team iounmap(hba->u.mv.mu);
66900f59701SHighPoint Linux Team }
67000f59701SHighPoint Linux Team
hptiop_unmap_pci_bar_mvfrey(struct hptiop_hba * hba)671286aa031SHighPoint Linux Team static void hptiop_unmap_pci_bar_mvfrey(struct hptiop_hba *hba)
672286aa031SHighPoint Linux Team {
673286aa031SHighPoint Linux Team iounmap(hba->u.mvfrey.config);
674286aa031SHighPoint Linux Team iounmap(hba->u.mvfrey.mu);
675286aa031SHighPoint Linux Team }
676286aa031SHighPoint Linux Team
hptiop_message_callback(struct hptiop_hba * hba,u32 msg)677ede1e6f8SHighPoint Linux Team static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg)
678ede1e6f8SHighPoint Linux Team {
679ede1e6f8SHighPoint Linux Team dprintk("iop message 0x%x\n", msg);
680ede1e6f8SHighPoint Linux Team
681286aa031SHighPoint Linux Team if (msg == IOPMU_INBOUND_MSG0_NOP ||
682286aa031SHighPoint Linux Team msg == IOPMU_INBOUND_MSG0_RESET_COMM)
68300f59701SHighPoint Linux Team hba->msg_done = 1;
68400f59701SHighPoint Linux Team
685ede1e6f8SHighPoint Linux Team if (!hba->initialized)
686ede1e6f8SHighPoint Linux Team return;
687ede1e6f8SHighPoint Linux Team
688ede1e6f8SHighPoint Linux Team if (msg == IOPMU_INBOUND_MSG0_RESET) {
689ede1e6f8SHighPoint Linux Team atomic_set(&hba->resetting, 0);
690ede1e6f8SHighPoint Linux Team wake_up(&hba->reset_wq);
691ede1e6f8SHighPoint Linux Team }
692ede1e6f8SHighPoint Linux Team else if (msg <= IOPMU_INBOUND_MSG0_MAX)
693ede1e6f8SHighPoint Linux Team hba->msg_done = 1;
694ede1e6f8SHighPoint Linux Team }
695ede1e6f8SHighPoint Linux Team
get_req(struct hptiop_hba * hba)69600f59701SHighPoint Linux Team static struct hptiop_request *get_req(struct hptiop_hba *hba)
697ede1e6f8SHighPoint Linux Team {
698ede1e6f8SHighPoint Linux Team struct hptiop_request *ret;
699ede1e6f8SHighPoint Linux Team
700ede1e6f8SHighPoint Linux Team dprintk("get_req : req=%p\n", hba->req_list);
701ede1e6f8SHighPoint Linux Team
702ede1e6f8SHighPoint Linux Team ret = hba->req_list;
703ede1e6f8SHighPoint Linux Team if (ret)
704ede1e6f8SHighPoint Linux Team hba->req_list = ret->next;
705ede1e6f8SHighPoint Linux Team
706ede1e6f8SHighPoint Linux Team return ret;
707ede1e6f8SHighPoint Linux Team }
708ede1e6f8SHighPoint Linux Team
free_req(struct hptiop_hba * hba,struct hptiop_request * req)70900f59701SHighPoint Linux Team static void free_req(struct hptiop_hba *hba, struct hptiop_request *req)
710ede1e6f8SHighPoint Linux Team {
711ede1e6f8SHighPoint Linux Team dprintk("free_req(%d, %p)\n", req->index, req);
712ede1e6f8SHighPoint Linux Team req->next = hba->req_list;
713ede1e6f8SHighPoint Linux Team hba->req_list = req;
714ede1e6f8SHighPoint Linux Team }
715ede1e6f8SHighPoint Linux Team
hptiop_finish_scsi_req(struct hptiop_hba * hba,u32 tag,struct hpt_iop_request_scsi_command * req)71600f59701SHighPoint Linux Team static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
71700f59701SHighPoint Linux Team struct hpt_iop_request_scsi_command *req)
718ede1e6f8SHighPoint Linux Team {
719ede1e6f8SHighPoint Linux Team struct scsi_cmnd *scp;
720ede1e6f8SHighPoint Linux Team
72100f59701SHighPoint Linux Team dprintk("hptiop_finish_scsi_req: req=%p, type=%d, "
722ede1e6f8SHighPoint Linux Team "result=%d, context=0x%x tag=%d\n",
723ede1e6f8SHighPoint Linux Team req, req->header.type, req->header.result,
724ede1e6f8SHighPoint Linux Team req->header.context, tag);
725ede1e6f8SHighPoint Linux Team
726ede1e6f8SHighPoint Linux Team BUG_ON(!req->header.result);
727ede1e6f8SHighPoint Linux Team BUG_ON(req->header.type != cpu_to_le32(IOP_REQUEST_TYPE_SCSI_COMMAND));
728ede1e6f8SHighPoint Linux Team
729ede1e6f8SHighPoint Linux Team scp = hba->reqs[tag].scp;
730ede1e6f8SHighPoint Linux Team
731f9875496SFUJITA Tomonori if (HPT_SCP(scp)->mapped)
732f9875496SFUJITA Tomonori scsi_dma_unmap(scp);
733ede1e6f8SHighPoint Linux Team
734ede1e6f8SHighPoint Linux Team switch (le32_to_cpu(req->header.result)) {
735ede1e6f8SHighPoint Linux Team case IOP_RESULT_SUCCESS:
73600f59701SHighPoint Linux Team scsi_set_resid(scp,
73700f59701SHighPoint Linux Team scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
738ede1e6f8SHighPoint Linux Team scp->result = (DID_OK<<16);
739ede1e6f8SHighPoint Linux Team break;
740ede1e6f8SHighPoint Linux Team case IOP_RESULT_BAD_TARGET:
741ede1e6f8SHighPoint Linux Team scp->result = (DID_BAD_TARGET<<16);
742ede1e6f8SHighPoint Linux Team break;
743ede1e6f8SHighPoint Linux Team case IOP_RESULT_BUSY:
744ede1e6f8SHighPoint Linux Team scp->result = (DID_BUS_BUSY<<16);
745ede1e6f8SHighPoint Linux Team break;
746ede1e6f8SHighPoint Linux Team case IOP_RESULT_RESET:
747ede1e6f8SHighPoint Linux Team scp->result = (DID_RESET<<16);
748ede1e6f8SHighPoint Linux Team break;
749ede1e6f8SHighPoint Linux Team case IOP_RESULT_FAIL:
750ede1e6f8SHighPoint Linux Team scp->result = (DID_ERROR<<16);
751ede1e6f8SHighPoint Linux Team break;
752ede1e6f8SHighPoint Linux Team case IOP_RESULT_INVALID_REQUEST:
753ede1e6f8SHighPoint Linux Team scp->result = (DID_ABORT<<16);
754ede1e6f8SHighPoint Linux Team break;
75500f59701SHighPoint Linux Team case IOP_RESULT_CHECK_CONDITION:
75600f59701SHighPoint Linux Team scsi_set_resid(scp,
75700f59701SHighPoint Linux Team scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
758ede1e6f8SHighPoint Linux Team scp->result = SAM_STAT_CHECK_CONDITION;
759a93429c3Slinux memcpy(scp->sense_buffer, &req->sg_list, SCSI_SENSE_BUFFERSIZE);
760286aa031SHighPoint Linux Team goto skip_resid;
761ede1e6f8SHighPoint Linux Team
762ede1e6f8SHighPoint Linux Team default:
76316576ad8SHannes Reinecke scp->result = DID_ABORT << 16;
764ede1e6f8SHighPoint Linux Team break;
765ede1e6f8SHighPoint Linux Team }
766ede1e6f8SHighPoint Linux Team
767286aa031SHighPoint Linux Team scsi_set_resid(scp,
768286aa031SHighPoint Linux Team scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
769286aa031SHighPoint Linux Team
770286aa031SHighPoint Linux Team skip_resid:
771ede1e6f8SHighPoint Linux Team dprintk("scsi_done(%p)\n", scp);
772574015a8SBart Van Assche scsi_done(scp);
773ede1e6f8SHighPoint Linux Team free_req(hba, &hba->reqs[tag]);
774ede1e6f8SHighPoint Linux Team }
775ede1e6f8SHighPoint Linux Team
hptiop_host_request_callback_itl(struct hptiop_hba * hba,u32 _tag)77600f59701SHighPoint Linux Team static void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 _tag)
77700f59701SHighPoint Linux Team {
77800f59701SHighPoint Linux Team struct hpt_iop_request_scsi_command *req;
77900f59701SHighPoint Linux Team u32 tag;
78000f59701SHighPoint Linux Team
78100f59701SHighPoint Linux Team if (hba->iopintf_v2) {
78200f59701SHighPoint Linux Team tag = _tag & ~IOPMU_QUEUE_REQUEST_RESULT_BIT;
78300f59701SHighPoint Linux Team req = hba->reqs[tag].req_virt;
78400f59701SHighPoint Linux Team if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT))
78500f59701SHighPoint Linux Team req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS);
78600f59701SHighPoint Linux Team } else {
78700f59701SHighPoint Linux Team tag = _tag;
78800f59701SHighPoint Linux Team req = hba->reqs[tag].req_virt;
78900f59701SHighPoint Linux Team }
79000f59701SHighPoint Linux Team
79100f59701SHighPoint Linux Team hptiop_finish_scsi_req(hba, tag, req);
79200f59701SHighPoint Linux Team }
79300f59701SHighPoint Linux Team
hptiop_iop_request_callback_itl(struct hptiop_hba * hba,u32 tag)79406d9eb4eSColin Ian King static void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag)
795ede1e6f8SHighPoint Linux Team {
796ede1e6f8SHighPoint Linux Team struct hpt_iop_request_header __iomem *req;
797ede1e6f8SHighPoint Linux Team struct hpt_iop_request_ioctl_command __iomem *p;
798ede1e6f8SHighPoint Linux Team struct hpt_ioctl_k *arg;
799ede1e6f8SHighPoint Linux Team
800ede1e6f8SHighPoint Linux Team req = (struct hpt_iop_request_header __iomem *)
80100f59701SHighPoint Linux Team ((unsigned long)hba->u.itl.iop + tag);
80200f59701SHighPoint Linux Team dprintk("hptiop_iop_request_callback_itl: req=%p, type=%d, "
803ede1e6f8SHighPoint Linux Team "result=%d, context=0x%x tag=%d\n",
804ede1e6f8SHighPoint Linux Team req, readl(&req->type), readl(&req->result),
805ede1e6f8SHighPoint Linux Team readl(&req->context), tag);
806ede1e6f8SHighPoint Linux Team
807ede1e6f8SHighPoint Linux Team BUG_ON(!readl(&req->result));
808ede1e6f8SHighPoint Linux Team BUG_ON(readl(&req->type) != IOP_REQUEST_TYPE_IOCTL_COMMAND);
809ede1e6f8SHighPoint Linux Team
810ede1e6f8SHighPoint Linux Team p = (struct hpt_iop_request_ioctl_command __iomem *)req;
811ede1e6f8SHighPoint Linux Team arg = (struct hpt_ioctl_k *)(unsigned long)
812ede1e6f8SHighPoint Linux Team (readl(&req->context) |
813ede1e6f8SHighPoint Linux Team ((u64)readl(&req->context_hi32)<<32));
814ede1e6f8SHighPoint Linux Team
815ede1e6f8SHighPoint Linux Team if (readl(&req->result) == IOP_RESULT_SUCCESS) {
816ede1e6f8SHighPoint Linux Team arg->result = HPT_IOCTL_RESULT_OK;
817ede1e6f8SHighPoint Linux Team
818ede1e6f8SHighPoint Linux Team if (arg->outbuf_size)
819ede1e6f8SHighPoint Linux Team memcpy_fromio(arg->outbuf,
820ede1e6f8SHighPoint Linux Team &p->buf[(readl(&p->inbuf_size) + 3)& ~3],
821ede1e6f8SHighPoint Linux Team arg->outbuf_size);
822ede1e6f8SHighPoint Linux Team
823ede1e6f8SHighPoint Linux Team if (arg->bytes_returned)
824ede1e6f8SHighPoint Linux Team *arg->bytes_returned = arg->outbuf_size;
825ede1e6f8SHighPoint Linux Team }
826ede1e6f8SHighPoint Linux Team else
827ede1e6f8SHighPoint Linux Team arg->result = HPT_IOCTL_RESULT_FAILED;
828ede1e6f8SHighPoint Linux Team
829ede1e6f8SHighPoint Linux Team arg->done(arg);
83000f59701SHighPoint Linux Team writel(tag, &hba->u.itl.iop->outbound_queue);
831ede1e6f8SHighPoint Linux Team }
832ede1e6f8SHighPoint Linux Team
hptiop_intr(int irq,void * dev_id)8337d12e780SDavid Howells static irqreturn_t hptiop_intr(int irq, void *dev_id)
834ede1e6f8SHighPoint Linux Team {
835ede1e6f8SHighPoint Linux Team struct hptiop_hba *hba = dev_id;
836ede1e6f8SHighPoint Linux Team int handled;
837ede1e6f8SHighPoint Linux Team unsigned long flags;
838ede1e6f8SHighPoint Linux Team
839ede1e6f8SHighPoint Linux Team spin_lock_irqsave(hba->host->host_lock, flags);
84000f59701SHighPoint Linux Team handled = hba->ops->iop_intr(hba);
841ede1e6f8SHighPoint Linux Team spin_unlock_irqrestore(hba->host->host_lock, flags);
842ede1e6f8SHighPoint Linux Team
843ede1e6f8SHighPoint Linux Team return handled;
844ede1e6f8SHighPoint Linux Team }
845ede1e6f8SHighPoint Linux Team
hptiop_buildsgl(struct scsi_cmnd * scp,struct hpt_iopsg * psg)846ede1e6f8SHighPoint Linux Team static int hptiop_buildsgl(struct scsi_cmnd *scp, struct hpt_iopsg *psg)
847ede1e6f8SHighPoint Linux Team {
848ede1e6f8SHighPoint Linux Team struct Scsi_Host *host = scp->device->host;
849ede1e6f8SHighPoint Linux Team struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
850f9875496SFUJITA Tomonori struct scatterlist *sg;
851f9875496SFUJITA Tomonori int idx, nseg;
852ede1e6f8SHighPoint Linux Team
853f9875496SFUJITA Tomonori nseg = scsi_dma_map(scp);
854f9875496SFUJITA Tomonori BUG_ON(nseg < 0);
855f9875496SFUJITA Tomonori if (!nseg)
856f9875496SFUJITA Tomonori return 0;
857ede1e6f8SHighPoint Linux Team
858f9875496SFUJITA Tomonori HPT_SCP(scp)->sgcnt = nseg;
859ede1e6f8SHighPoint Linux Team HPT_SCP(scp)->mapped = 1;
860f9875496SFUJITA Tomonori
861ede1e6f8SHighPoint Linux Team BUG_ON(HPT_SCP(scp)->sgcnt > hba->max_sg_descriptors);
862ede1e6f8SHighPoint Linux Team
863f9875496SFUJITA Tomonori scsi_for_each_sg(scp, sg, HPT_SCP(scp)->sgcnt, idx) {
864286aa031SHighPoint Linux Team psg[idx].pci_address = cpu_to_le64(sg_dma_address(sg)) |
865286aa031SHighPoint Linux Team hba->ops->host_phy_flag;
866f9875496SFUJITA Tomonori psg[idx].size = cpu_to_le32(sg_dma_len(sg));
867ede1e6f8SHighPoint Linux Team psg[idx].eot = (idx == HPT_SCP(scp)->sgcnt - 1) ?
868ede1e6f8SHighPoint Linux Team cpu_to_le32(1) : 0;
869ede1e6f8SHighPoint Linux Team }
870ede1e6f8SHighPoint Linux Team return HPT_SCP(scp)->sgcnt;
871ede1e6f8SHighPoint Linux Team }
872ede1e6f8SHighPoint Linux Team
hptiop_post_req_itl(struct hptiop_hba * hba,struct hptiop_request * _req)87300f59701SHighPoint Linux Team static void hptiop_post_req_itl(struct hptiop_hba *hba,
87400f59701SHighPoint Linux Team struct hptiop_request *_req)
87500f59701SHighPoint Linux Team {
87600f59701SHighPoint Linux Team struct hpt_iop_request_header *reqhdr = _req->req_virt;
87700f59701SHighPoint Linux Team
87800f59701SHighPoint Linux Team reqhdr->context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT |
87900f59701SHighPoint Linux Team (u32)_req->index);
88000f59701SHighPoint Linux Team reqhdr->context_hi32 = 0;
88100f59701SHighPoint Linux Team
88200f59701SHighPoint Linux Team if (hba->iopintf_v2) {
88300f59701SHighPoint Linux Team u32 size, size_bits;
88400f59701SHighPoint Linux Team
88500f59701SHighPoint Linux Team size = le32_to_cpu(reqhdr->size);
88600f59701SHighPoint Linux Team if (size < 256)
88700f59701SHighPoint Linux Team size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
88800f59701SHighPoint Linux Team else if (size < 512)
88900f59701SHighPoint Linux Team size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
89000f59701SHighPoint Linux Team else
89100f59701SHighPoint Linux Team size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT |
89200f59701SHighPoint Linux Team IOPMU_QUEUE_ADDR_HOST_BIT;
89300f59701SHighPoint Linux Team writel(_req->req_shifted_phy | size_bits,
89400f59701SHighPoint Linux Team &hba->u.itl.iop->inbound_queue);
89500f59701SHighPoint Linux Team } else
89600f59701SHighPoint Linux Team writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT,
89700f59701SHighPoint Linux Team &hba->u.itl.iop->inbound_queue);
89800f59701SHighPoint Linux Team }
89900f59701SHighPoint Linux Team
hptiop_post_req_mv(struct hptiop_hba * hba,struct hptiop_request * _req)90000f59701SHighPoint Linux Team static void hptiop_post_req_mv(struct hptiop_hba *hba,
90100f59701SHighPoint Linux Team struct hptiop_request *_req)
90200f59701SHighPoint Linux Team {
90300f59701SHighPoint Linux Team struct hpt_iop_request_header *reqhdr = _req->req_virt;
90400f59701SHighPoint Linux Team u32 size, size_bit;
90500f59701SHighPoint Linux Team
90600f59701SHighPoint Linux Team reqhdr->context = cpu_to_le32(_req->index<<8 |
90700f59701SHighPoint Linux Team IOP_REQUEST_TYPE_SCSI_COMMAND<<5);
90800f59701SHighPoint Linux Team reqhdr->context_hi32 = 0;
90900f59701SHighPoint Linux Team size = le32_to_cpu(reqhdr->size);
91000f59701SHighPoint Linux Team
91100f59701SHighPoint Linux Team if (size <= 256)
91200f59701SHighPoint Linux Team size_bit = 0;
91300f59701SHighPoint Linux Team else if (size <= 256*2)
91400f59701SHighPoint Linux Team size_bit = 1;
91500f59701SHighPoint Linux Team else if (size <= 256*3)
91600f59701SHighPoint Linux Team size_bit = 2;
91700f59701SHighPoint Linux Team else
91800f59701SHighPoint Linux Team size_bit = 3;
91900f59701SHighPoint Linux Team
92000f59701SHighPoint Linux Team mv_inbound_write((_req->req_shifted_phy << 5) |
92100f59701SHighPoint Linux Team MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bit, hba);
92200f59701SHighPoint Linux Team }
92300f59701SHighPoint Linux Team
hptiop_post_req_mvfrey(struct hptiop_hba * hba,struct hptiop_request * _req)924286aa031SHighPoint Linux Team static void hptiop_post_req_mvfrey(struct hptiop_hba *hba,
925286aa031SHighPoint Linux Team struct hptiop_request *_req)
926286aa031SHighPoint Linux Team {
927286aa031SHighPoint Linux Team struct hpt_iop_request_header *reqhdr = _req->req_virt;
928286aa031SHighPoint Linux Team u32 index;
929286aa031SHighPoint Linux Team
930286aa031SHighPoint Linux Team reqhdr->flags |= cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT |
931286aa031SHighPoint Linux Team IOP_REQUEST_FLAG_ADDR_BITS |
932286aa031SHighPoint Linux Team ((_req->req_shifted_phy >> 11) & 0xffff0000));
933286aa031SHighPoint Linux Team reqhdr->context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT |
934286aa031SHighPoint Linux Team (_req->index << 4) | reqhdr->type);
935286aa031SHighPoint Linux Team reqhdr->context_hi32 = cpu_to_le32((_req->req_shifted_phy << 5) &
936286aa031SHighPoint Linux Team 0xffffffff);
937286aa031SHighPoint Linux Team
938286aa031SHighPoint Linux Team hba->u.mvfrey.inlist_wptr++;
939286aa031SHighPoint Linux Team index = hba->u.mvfrey.inlist_wptr & 0x3fff;
940286aa031SHighPoint Linux Team
941286aa031SHighPoint Linux Team if (index == hba->u.mvfrey.list_count) {
942286aa031SHighPoint Linux Team index = 0;
943286aa031SHighPoint Linux Team hba->u.mvfrey.inlist_wptr &= ~0x3fff;
944286aa031SHighPoint Linux Team hba->u.mvfrey.inlist_wptr ^= CL_POINTER_TOGGLE;
945286aa031SHighPoint Linux Team }
946286aa031SHighPoint Linux Team
947286aa031SHighPoint Linux Team hba->u.mvfrey.inlist[index].addr =
948286aa031SHighPoint Linux Team (dma_addr_t)_req->req_shifted_phy << 5;
949286aa031SHighPoint Linux Team hba->u.mvfrey.inlist[index].intrfc_len = (reqhdr->size + 3) / 4;
950286aa031SHighPoint Linux Team writel(hba->u.mvfrey.inlist_wptr,
951286aa031SHighPoint Linux Team &(hba->u.mvfrey.mu->inbound_write_ptr));
952286aa031SHighPoint Linux Team readl(&(hba->u.mvfrey.mu->inbound_write_ptr));
953286aa031SHighPoint Linux Team }
954286aa031SHighPoint Linux Team
hptiop_reset_comm_itl(struct hptiop_hba * hba)955286aa031SHighPoint Linux Team static int hptiop_reset_comm_itl(struct hptiop_hba *hba)
956286aa031SHighPoint Linux Team {
957286aa031SHighPoint Linux Team return 0;
958286aa031SHighPoint Linux Team }
959286aa031SHighPoint Linux Team
hptiop_reset_comm_mv(struct hptiop_hba * hba)960286aa031SHighPoint Linux Team static int hptiop_reset_comm_mv(struct hptiop_hba *hba)
961286aa031SHighPoint Linux Team {
962286aa031SHighPoint Linux Team return 0;
963286aa031SHighPoint Linux Team }
964286aa031SHighPoint Linux Team
hptiop_reset_comm_mvfrey(struct hptiop_hba * hba)965286aa031SHighPoint Linux Team static int hptiop_reset_comm_mvfrey(struct hptiop_hba *hba)
966286aa031SHighPoint Linux Team {
967286aa031SHighPoint Linux Team u32 list_count = hba->u.mvfrey.list_count;
968286aa031SHighPoint Linux Team
969286aa031SHighPoint Linux Team if (iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_RESET_COMM, 3000))
970286aa031SHighPoint Linux Team return -1;
971286aa031SHighPoint Linux Team
972286aa031SHighPoint Linux Team /* wait 100ms for MCU ready */
973286aa031SHighPoint Linux Team msleep(100);
974286aa031SHighPoint Linux Team
975286aa031SHighPoint Linux Team writel(cpu_to_le32(hba->u.mvfrey.inlist_phy & 0xffffffff),
976286aa031SHighPoint Linux Team &(hba->u.mvfrey.mu->inbound_base));
977286aa031SHighPoint Linux Team writel(cpu_to_le32((hba->u.mvfrey.inlist_phy >> 16) >> 16),
978286aa031SHighPoint Linux Team &(hba->u.mvfrey.mu->inbound_base_high));
979286aa031SHighPoint Linux Team
980286aa031SHighPoint Linux Team writel(cpu_to_le32(hba->u.mvfrey.outlist_phy & 0xffffffff),
981286aa031SHighPoint Linux Team &(hba->u.mvfrey.mu->outbound_base));
982286aa031SHighPoint Linux Team writel(cpu_to_le32((hba->u.mvfrey.outlist_phy >> 16) >> 16),
983286aa031SHighPoint Linux Team &(hba->u.mvfrey.mu->outbound_base_high));
984286aa031SHighPoint Linux Team
985286aa031SHighPoint Linux Team writel(cpu_to_le32(hba->u.mvfrey.outlist_cptr_phy & 0xffffffff),
986286aa031SHighPoint Linux Team &(hba->u.mvfrey.mu->outbound_shadow_base));
987286aa031SHighPoint Linux Team writel(cpu_to_le32((hba->u.mvfrey.outlist_cptr_phy >> 16) >> 16),
988286aa031SHighPoint Linux Team &(hba->u.mvfrey.mu->outbound_shadow_base_high));
989286aa031SHighPoint Linux Team
990286aa031SHighPoint Linux Team hba->u.mvfrey.inlist_wptr = (list_count - 1) | CL_POINTER_TOGGLE;
991286aa031SHighPoint Linux Team *hba->u.mvfrey.outlist_cptr = (list_count - 1) | CL_POINTER_TOGGLE;
992286aa031SHighPoint Linux Team hba->u.mvfrey.outlist_rptr = list_count - 1;
993286aa031SHighPoint Linux Team return 0;
994286aa031SHighPoint Linux Team }
995286aa031SHighPoint Linux Team
hptiop_queuecommand_lck(struct scsi_cmnd * scp)996af049dfdSBart Van Assche static int hptiop_queuecommand_lck(struct scsi_cmnd *scp)
997ede1e6f8SHighPoint Linux Team {
998ede1e6f8SHighPoint Linux Team struct Scsi_Host *host = scp->device->host;
999ede1e6f8SHighPoint Linux Team struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
1000ede1e6f8SHighPoint Linux Team struct hpt_iop_request_scsi_command *req;
1001ede1e6f8SHighPoint Linux Team int sg_count = 0;
1002ede1e6f8SHighPoint Linux Team struct hptiop_request *_req;
1003ede1e6f8SHighPoint Linux Team
1004ede1e6f8SHighPoint Linux Team _req = get_req(hba);
1005ede1e6f8SHighPoint Linux Team if (_req == NULL) {
1006ede1e6f8SHighPoint Linux Team dprintk("hptiop_queuecmd : no free req\n");
10074f2ddba3SHighPoint Linux Team return SCSI_MLQUEUE_HOST_BUSY;
1008ede1e6f8SHighPoint Linux Team }
1009ede1e6f8SHighPoint Linux Team
1010ede1e6f8SHighPoint Linux Team _req->scp = scp;
1011ede1e6f8SHighPoint Linux Team
10129cb78c16SHannes Reinecke dprintk("hptiop_queuecmd(scp=%p) %d/%d/%d/%llu cdb=(%08x-%08x-%08x-%08x) "
1013ede1e6f8SHighPoint Linux Team "req_index=%d, req=%p\n",
1014ede1e6f8SHighPoint Linux Team scp,
1015ede1e6f8SHighPoint Linux Team host->host_no, scp->device->channel,
1016ede1e6f8SHighPoint Linux Team scp->device->id, scp->device->lun,
1017286aa031SHighPoint Linux Team cpu_to_be32(((u32 *)scp->cmnd)[0]),
1018286aa031SHighPoint Linux Team cpu_to_be32(((u32 *)scp->cmnd)[1]),
1019286aa031SHighPoint Linux Team cpu_to_be32(((u32 *)scp->cmnd)[2]),
1020286aa031SHighPoint Linux Team cpu_to_be32(((u32 *)scp->cmnd)[3]),
1021ede1e6f8SHighPoint Linux Team _req->index, _req->req_virt);
1022ede1e6f8SHighPoint Linux Team
1023ede1e6f8SHighPoint Linux Team scp->result = 0;
1024ede1e6f8SHighPoint Linux Team
1025a93429c3Slinux if (scp->device->channel ||
1026a93429c3Slinux (scp->device->id > hba->max_devices) ||
1027a93429c3Slinux ((scp->device->id == (hba->max_devices-1)) && scp->device->lun)) {
1028ede1e6f8SHighPoint Linux Team scp->result = DID_BAD_TARGET << 16;
1029ede1e6f8SHighPoint Linux Team free_req(hba, _req);
1030ede1e6f8SHighPoint Linux Team goto cmd_done;
1031ede1e6f8SHighPoint Linux Team }
1032ede1e6f8SHighPoint Linux Team
1033db9b6e89SHighPoint Linux Team req = _req->req_virt;
1034ede1e6f8SHighPoint Linux Team
1035ede1e6f8SHighPoint Linux Team /* build S/G table */
1036ede1e6f8SHighPoint Linux Team sg_count = hptiop_buildsgl(scp, req->sg_list);
1037f9875496SFUJITA Tomonori if (!sg_count)
1038ede1e6f8SHighPoint Linux Team HPT_SCP(scp)->mapped = 0;
1039ede1e6f8SHighPoint Linux Team
1040ede1e6f8SHighPoint Linux Team req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
1041ede1e6f8SHighPoint Linux Team req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SCSI_COMMAND);
1042ede1e6f8SHighPoint Linux Team req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
1043f9875496SFUJITA Tomonori req->dataxfer_length = cpu_to_le32(scsi_bufflen(scp));
1044ede1e6f8SHighPoint Linux Team req->channel = scp->device->channel;
1045ede1e6f8SHighPoint Linux Team req->target = scp->device->id;
1046ede1e6f8SHighPoint Linux Team req->lun = scp->device->lun;
10475b12a568SGustavo A. R. Silva req->header.size = cpu_to_le32(struct_size(req, sg_list, sg_count));
1048ede1e6f8SHighPoint Linux Team
1049ede1e6f8SHighPoint Linux Team memcpy(req->cdb, scp->cmnd, sizeof(req->cdb));
105000f59701SHighPoint Linux Team hba->ops->post_req(hba, _req);
1051ede1e6f8SHighPoint Linux Team return 0;
1052ede1e6f8SHighPoint Linux Team
1053ede1e6f8SHighPoint Linux Team cmd_done:
1054ede1e6f8SHighPoint Linux Team dprintk("scsi_done(scp=%p)\n", scp);
1055574015a8SBart Van Assche scsi_done(scp);
1056ede1e6f8SHighPoint Linux Team return 0;
1057ede1e6f8SHighPoint Linux Team }
1058ede1e6f8SHighPoint Linux Team
DEF_SCSI_QCMD(hptiop_queuecommand)1059f281233dSJeff Garzik static DEF_SCSI_QCMD(hptiop_queuecommand)
1060f281233dSJeff Garzik
1061ede1e6f8SHighPoint Linux Team static const char *hptiop_info(struct Scsi_Host *host)
1062ede1e6f8SHighPoint Linux Team {
1063ede1e6f8SHighPoint Linux Team return driver_name_long;
1064ede1e6f8SHighPoint Linux Team }
1065ede1e6f8SHighPoint Linux Team
hptiop_reset_hba(struct hptiop_hba * hba)1066ede1e6f8SHighPoint Linux Team static int hptiop_reset_hba(struct hptiop_hba *hba)
1067ede1e6f8SHighPoint Linux Team {
1068ede1e6f8SHighPoint Linux Team if (atomic_xchg(&hba->resetting, 1) == 0) {
1069ede1e6f8SHighPoint Linux Team atomic_inc(&hba->reset_count);
107000f59701SHighPoint Linux Team hba->ops->post_msg(hba, IOPMU_INBOUND_MSG0_RESET);
1071ede1e6f8SHighPoint Linux Team }
1072ede1e6f8SHighPoint Linux Team
1073ede1e6f8SHighPoint Linux Team wait_event_timeout(hba->reset_wq,
1074ede1e6f8SHighPoint Linux Team atomic_read(&hba->resetting) == 0, 60 * HZ);
1075ede1e6f8SHighPoint Linux Team
1076ede1e6f8SHighPoint Linux Team if (atomic_read(&hba->resetting)) {
1077af901ca1SAndré Goddard Rosa /* IOP is in unknown state, abort reset */
1078ede1e6f8SHighPoint Linux Team printk(KERN_ERR "scsi%d: reset failed\n", hba->host->host_no);
1079ede1e6f8SHighPoint Linux Team return -1;
1080ede1e6f8SHighPoint Linux Team }
1081ede1e6f8SHighPoint Linux Team
1082ede1e6f8SHighPoint Linux Team if (iop_send_sync_msg(hba,
1083ede1e6f8SHighPoint Linux Team IOPMU_INBOUND_MSG0_START_BACKGROUND_TASK, 5000)) {
1084ede1e6f8SHighPoint Linux Team dprintk("scsi%d: fail to start background task\n",
1085ede1e6f8SHighPoint Linux Team hba->host->host_no);
1086ede1e6f8SHighPoint Linux Team }
1087ede1e6f8SHighPoint Linux Team
1088ede1e6f8SHighPoint Linux Team return 0;
1089ede1e6f8SHighPoint Linux Team }
1090ede1e6f8SHighPoint Linux Team
hptiop_reset(struct scsi_cmnd * scp)1091ede1e6f8SHighPoint Linux Team static int hptiop_reset(struct scsi_cmnd *scp)
1092ede1e6f8SHighPoint Linux Team {
1093aceb2948SHannes Reinecke struct hptiop_hba * hba = (struct hptiop_hba *)scp->device->host->hostdata;
1094ede1e6f8SHighPoint Linux Team
1095aceb2948SHannes Reinecke printk(KERN_WARNING "hptiop_reset(%d/%d/%d)\n",
1096aceb2948SHannes Reinecke scp->device->host->host_no, -1, -1);
1097ede1e6f8SHighPoint Linux Team
1098ede1e6f8SHighPoint Linux Team return hptiop_reset_hba(hba)? FAILED : SUCCESS;
1099ede1e6f8SHighPoint Linux Team }
1100ede1e6f8SHighPoint Linux Team
hptiop_adjust_disk_queue_depth(struct scsi_device * sdev,int queue_depth)1101ede1e6f8SHighPoint Linux Team static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev,
1102db5ed4dfSChristoph Hellwig int queue_depth)
1103ede1e6f8SHighPoint Linux Team {
110400f59701SHighPoint Linux Team struct hptiop_hba *hba = (struct hptiop_hba *)sdev->host->hostdata;
110500f59701SHighPoint Linux Team
110600f59701SHighPoint Linux Team if (queue_depth > hba->max_requests)
110700f59701SHighPoint Linux Team queue_depth = hba->max_requests;
1108db5ed4dfSChristoph Hellwig return scsi_change_queue_depth(sdev, queue_depth);
1109ede1e6f8SHighPoint Linux Team }
1110ede1e6f8SHighPoint Linux Team
hptiop_show_version(struct device * dev,struct device_attribute * attr,char * buf)1111ee959b00STony Jones static ssize_t hptiop_show_version(struct device *dev,
1112ee959b00STony Jones struct device_attribute *attr, char *buf)
1113ede1e6f8SHighPoint Linux Team {
1114ede1e6f8SHighPoint Linux Team return snprintf(buf, PAGE_SIZE, "%s\n", driver_ver);
1115ede1e6f8SHighPoint Linux Team }
1116ede1e6f8SHighPoint Linux Team
hptiop_show_fw_version(struct device * dev,struct device_attribute * attr,char * buf)1117ee959b00STony Jones static ssize_t hptiop_show_fw_version(struct device *dev,
1118ee959b00STony Jones struct device_attribute *attr, char *buf)
1119ede1e6f8SHighPoint Linux Team {
1120ee959b00STony Jones struct Scsi_Host *host = class_to_shost(dev);
1121ede1e6f8SHighPoint Linux Team struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
1122ede1e6f8SHighPoint Linux Team
1123ede1e6f8SHighPoint Linux Team return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n",
1124ede1e6f8SHighPoint Linux Team hba->firmware_version >> 24,
1125ede1e6f8SHighPoint Linux Team (hba->firmware_version >> 16) & 0xff,
1126ede1e6f8SHighPoint Linux Team (hba->firmware_version >> 8) & 0xff,
1127ede1e6f8SHighPoint Linux Team hba->firmware_version & 0xff);
1128ede1e6f8SHighPoint Linux Team }
1129ede1e6f8SHighPoint Linux Team
1130ee959b00STony Jones static struct device_attribute hptiop_attr_version = {
1131ede1e6f8SHighPoint Linux Team .attr = {
1132ede1e6f8SHighPoint Linux Team .name = "driver-version",
1133ede1e6f8SHighPoint Linux Team .mode = S_IRUGO,
1134ede1e6f8SHighPoint Linux Team },
1135ede1e6f8SHighPoint Linux Team .show = hptiop_show_version,
1136ede1e6f8SHighPoint Linux Team };
1137ede1e6f8SHighPoint Linux Team
1138ee959b00STony Jones static struct device_attribute hptiop_attr_fw_version = {
1139ede1e6f8SHighPoint Linux Team .attr = {
1140ede1e6f8SHighPoint Linux Team .name = "firmware-version",
1141ede1e6f8SHighPoint Linux Team .mode = S_IRUGO,
1142ede1e6f8SHighPoint Linux Team },
1143ede1e6f8SHighPoint Linux Team .show = hptiop_show_fw_version,
1144ede1e6f8SHighPoint Linux Team };
1145ede1e6f8SHighPoint Linux Team
1146e8fbc28eSBart Van Assche static struct attribute *hptiop_host_attrs[] = {
1147e8fbc28eSBart Van Assche &hptiop_attr_version.attr,
1148e8fbc28eSBart Van Assche &hptiop_attr_fw_version.attr,
1149ede1e6f8SHighPoint Linux Team NULL
1150ede1e6f8SHighPoint Linux Team };
1151ede1e6f8SHighPoint Linux Team
1152e8fbc28eSBart Van Assche ATTRIBUTE_GROUPS(hptiop_host);
1153e8fbc28eSBart Van Assche
hptiop_slave_config(struct scsi_device * sdev)1154a93429c3Slinux static int hptiop_slave_config(struct scsi_device *sdev)
1155a93429c3Slinux {
1156a93429c3Slinux if (sdev->type == TYPE_TAPE)
1157a93429c3Slinux blk_queue_max_hw_sectors(sdev->request_queue, 8192);
1158a93429c3Slinux
1159a93429c3Slinux return 0;
1160a93429c3Slinux }
1161a93429c3Slinux
1162*9194970bSBart Van Assche static const struct scsi_host_template driver_template = {
1163ede1e6f8SHighPoint Linux Team .module = THIS_MODULE,
1164ede1e6f8SHighPoint Linux Team .name = driver_name,
1165ede1e6f8SHighPoint Linux Team .queuecommand = hptiop_queuecommand,
1166aceb2948SHannes Reinecke .eh_host_reset_handler = hptiop_reset,
1167ede1e6f8SHighPoint Linux Team .info = hptiop_info,
1168ede1e6f8SHighPoint Linux Team .emulated = 0,
1169ede1e6f8SHighPoint Linux Team .proc_name = driver_name,
1170e8fbc28eSBart Van Assche .shost_groups = hptiop_host_groups,
1171a93429c3Slinux .slave_configure = hptiop_slave_config,
1172ede1e6f8SHighPoint Linux Team .this_id = -1,
1173ede1e6f8SHighPoint Linux Team .change_queue_depth = hptiop_adjust_disk_queue_depth,
11745c113eb3SBart Van Assche .cmd_size = sizeof(struct hpt_cmd_priv),
1175ede1e6f8SHighPoint Linux Team };
1176ede1e6f8SHighPoint Linux Team
hptiop_internal_memalloc_itl(struct hptiop_hba * hba)1177286aa031SHighPoint Linux Team static int hptiop_internal_memalloc_itl(struct hptiop_hba *hba)
1178286aa031SHighPoint Linux Team {
1179286aa031SHighPoint Linux Team return 0;
1180286aa031SHighPoint Linux Team }
1181286aa031SHighPoint Linux Team
hptiop_internal_memalloc_mv(struct hptiop_hba * hba)118200f59701SHighPoint Linux Team static int hptiop_internal_memalloc_mv(struct hptiop_hba *hba)
118300f59701SHighPoint Linux Team {
118400f59701SHighPoint Linux Team hba->u.mv.internal_req = dma_alloc_coherent(&hba->pcidev->dev,
118500f59701SHighPoint Linux Team 0x800, &hba->u.mv.internal_req_phy, GFP_KERNEL);
118600f59701SHighPoint Linux Team if (hba->u.mv.internal_req)
118700f59701SHighPoint Linux Team return 0;
118800f59701SHighPoint Linux Team else
118900f59701SHighPoint Linux Team return -1;
119000f59701SHighPoint Linux Team }
119100f59701SHighPoint Linux Team
hptiop_internal_memalloc_mvfrey(struct hptiop_hba * hba)1192286aa031SHighPoint Linux Team static int hptiop_internal_memalloc_mvfrey(struct hptiop_hba *hba)
1193286aa031SHighPoint Linux Team {
1194286aa031SHighPoint Linux Team u32 list_count = readl(&hba->u.mvfrey.mu->inbound_conf_ctl);
1195286aa031SHighPoint Linux Team char *p;
1196286aa031SHighPoint Linux Team dma_addr_t phy;
1197286aa031SHighPoint Linux Team
1198286aa031SHighPoint Linux Team BUG_ON(hba->max_request_size == 0);
1199286aa031SHighPoint Linux Team
1200286aa031SHighPoint Linux Team if (list_count == 0) {
1201286aa031SHighPoint Linux Team BUG_ON(1);
1202286aa031SHighPoint Linux Team return -1;
1203286aa031SHighPoint Linux Team }
1204286aa031SHighPoint Linux Team
1205286aa031SHighPoint Linux Team list_count >>= 16;
1206286aa031SHighPoint Linux Team
1207286aa031SHighPoint Linux Team hba->u.mvfrey.list_count = list_count;
1208286aa031SHighPoint Linux Team hba->u.mvfrey.internal_mem_size = 0x800 +
1209286aa031SHighPoint Linux Team list_count * sizeof(struct mvfrey_inlist_entry) +
1210286aa031SHighPoint Linux Team list_count * sizeof(struct mvfrey_outlist_entry) +
1211286aa031SHighPoint Linux Team sizeof(int);
1212286aa031SHighPoint Linux Team
1213286aa031SHighPoint Linux Team p = dma_alloc_coherent(&hba->pcidev->dev,
1214286aa031SHighPoint Linux Team hba->u.mvfrey.internal_mem_size, &phy, GFP_KERNEL);
1215286aa031SHighPoint Linux Team if (!p)
1216286aa031SHighPoint Linux Team return -1;
1217286aa031SHighPoint Linux Team
1218286aa031SHighPoint Linux Team hba->u.mvfrey.internal_req.req_virt = p;
1219286aa031SHighPoint Linux Team hba->u.mvfrey.internal_req.req_shifted_phy = phy >> 5;
1220286aa031SHighPoint Linux Team hba->u.mvfrey.internal_req.scp = NULL;
1221286aa031SHighPoint Linux Team hba->u.mvfrey.internal_req.next = NULL;
1222286aa031SHighPoint Linux Team
1223286aa031SHighPoint Linux Team p += 0x800;
1224286aa031SHighPoint Linux Team phy += 0x800;
1225286aa031SHighPoint Linux Team
1226286aa031SHighPoint Linux Team hba->u.mvfrey.inlist = (struct mvfrey_inlist_entry *)p;
1227286aa031SHighPoint Linux Team hba->u.mvfrey.inlist_phy = phy;
1228286aa031SHighPoint Linux Team
1229286aa031SHighPoint Linux Team p += list_count * sizeof(struct mvfrey_inlist_entry);
1230286aa031SHighPoint Linux Team phy += list_count * sizeof(struct mvfrey_inlist_entry);
1231286aa031SHighPoint Linux Team
1232286aa031SHighPoint Linux Team hba->u.mvfrey.outlist = (struct mvfrey_outlist_entry *)p;
1233286aa031SHighPoint Linux Team hba->u.mvfrey.outlist_phy = phy;
1234286aa031SHighPoint Linux Team
1235286aa031SHighPoint Linux Team p += list_count * sizeof(struct mvfrey_outlist_entry);
1236286aa031SHighPoint Linux Team phy += list_count * sizeof(struct mvfrey_outlist_entry);
1237286aa031SHighPoint Linux Team
1238286aa031SHighPoint Linux Team hba->u.mvfrey.outlist_cptr = (__le32 *)p;
1239286aa031SHighPoint Linux Team hba->u.mvfrey.outlist_cptr_phy = phy;
1240286aa031SHighPoint Linux Team
1241286aa031SHighPoint Linux Team return 0;
1242286aa031SHighPoint Linux Team }
1243286aa031SHighPoint Linux Team
hptiop_internal_memfree_itl(struct hptiop_hba * hba)1244286aa031SHighPoint Linux Team static int hptiop_internal_memfree_itl(struct hptiop_hba *hba)
1245286aa031SHighPoint Linux Team {
1246286aa031SHighPoint Linux Team return 0;
1247286aa031SHighPoint Linux Team }
1248286aa031SHighPoint Linux Team
hptiop_internal_memfree_mv(struct hptiop_hba * hba)124900f59701SHighPoint Linux Team static int hptiop_internal_memfree_mv(struct hptiop_hba *hba)
125000f59701SHighPoint Linux Team {
125100f59701SHighPoint Linux Team if (hba->u.mv.internal_req) {
125200f59701SHighPoint Linux Team dma_free_coherent(&hba->pcidev->dev, 0x800,
125300f59701SHighPoint Linux Team hba->u.mv.internal_req, hba->u.mv.internal_req_phy);
125400f59701SHighPoint Linux Team return 0;
125500f59701SHighPoint Linux Team } else
125600f59701SHighPoint Linux Team return -1;
125700f59701SHighPoint Linux Team }
125800f59701SHighPoint Linux Team
hptiop_internal_memfree_mvfrey(struct hptiop_hba * hba)1259286aa031SHighPoint Linux Team static int hptiop_internal_memfree_mvfrey(struct hptiop_hba *hba)
1260286aa031SHighPoint Linux Team {
1261286aa031SHighPoint Linux Team if (hba->u.mvfrey.internal_req.req_virt) {
1262286aa031SHighPoint Linux Team dma_free_coherent(&hba->pcidev->dev,
1263286aa031SHighPoint Linux Team hba->u.mvfrey.internal_mem_size,
1264286aa031SHighPoint Linux Team hba->u.mvfrey.internal_req.req_virt,
1265286aa031SHighPoint Linux Team (dma_addr_t)
1266286aa031SHighPoint Linux Team hba->u.mvfrey.internal_req.req_shifted_phy << 5);
1267286aa031SHighPoint Linux Team return 0;
1268286aa031SHighPoint Linux Team } else
1269286aa031SHighPoint Linux Team return -1;
1270286aa031SHighPoint Linux Team }
1271286aa031SHighPoint Linux Team
hptiop_probe(struct pci_dev * pcidev,const struct pci_device_id * id)12726f039790SGreg Kroah-Hartman static int hptiop_probe(struct pci_dev *pcidev, const struct pci_device_id *id)
1273ede1e6f8SHighPoint Linux Team {
1274ede1e6f8SHighPoint Linux Team struct Scsi_Host *host = NULL;
1275ede1e6f8SHighPoint Linux Team struct hptiop_hba *hba;
127623f0bb47SHighPoint Linux Team struct hptiop_adapter_ops *iop_ops;
1277ede1e6f8SHighPoint Linux Team struct hpt_iop_request_get_config iop_config;
1278ede1e6f8SHighPoint Linux Team struct hpt_iop_request_set_config set_config;
1279ede1e6f8SHighPoint Linux Team dma_addr_t start_phy;
1280ede1e6f8SHighPoint Linux Team void *start_virt;
1281ede1e6f8SHighPoint Linux Team u32 offset, i, req_size;
12823e344b6cSHannes Reinecke int rc;
1283ede1e6f8SHighPoint Linux Team
1284ede1e6f8SHighPoint Linux Team dprintk("hptiop_probe(%p)\n", pcidev);
1285ede1e6f8SHighPoint Linux Team
1286ede1e6f8SHighPoint Linux Team if (pci_enable_device(pcidev)) {
1287ede1e6f8SHighPoint Linux Team printk(KERN_ERR "hptiop: fail to enable pci device\n");
1288ede1e6f8SHighPoint Linux Team return -ENODEV;
1289ede1e6f8SHighPoint Linux Team }
1290ede1e6f8SHighPoint Linux Team
1291ede1e6f8SHighPoint Linux Team printk(KERN_INFO "adapter at PCI %d:%d:%d, IRQ %d\n",
1292ede1e6f8SHighPoint Linux Team pcidev->bus->number, pcidev->devfn >> 3, pcidev->devfn & 7,
1293ede1e6f8SHighPoint Linux Team pcidev->irq);
1294ede1e6f8SHighPoint Linux Team
1295ede1e6f8SHighPoint Linux Team pci_set_master(pcidev);
1296ede1e6f8SHighPoint Linux Team
1297ede1e6f8SHighPoint Linux Team /* Enable 64bit DMA if possible */
129823f0bb47SHighPoint Linux Team iop_ops = (struct hptiop_adapter_ops *)id->driver_data;
12993e344b6cSHannes Reinecke rc = dma_set_mask(&pcidev->dev,
13003e344b6cSHannes Reinecke DMA_BIT_MASK(iop_ops->hw_dma_bit_mask));
13013e344b6cSHannes Reinecke if (rc)
13023e344b6cSHannes Reinecke rc = dma_set_mask(&pcidev->dev, DMA_BIT_MASK(32));
13033e344b6cSHannes Reinecke
13043e344b6cSHannes Reinecke if (rc) {
1305ede1e6f8SHighPoint Linux Team printk(KERN_ERR "hptiop: fail to set dma_mask\n");
1306ede1e6f8SHighPoint Linux Team goto disable_pci_device;
1307ede1e6f8SHighPoint Linux Team }
1308ede1e6f8SHighPoint Linux Team
1309ede1e6f8SHighPoint Linux Team if (pci_request_regions(pcidev, driver_name)) {
1310ede1e6f8SHighPoint Linux Team printk(KERN_ERR "hptiop: pci_request_regions failed\n");
1311ede1e6f8SHighPoint Linux Team goto disable_pci_device;
1312ede1e6f8SHighPoint Linux Team }
1313ede1e6f8SHighPoint Linux Team
1314ede1e6f8SHighPoint Linux Team host = scsi_host_alloc(&driver_template, sizeof(struct hptiop_hba));
1315ede1e6f8SHighPoint Linux Team if (!host) {
1316ede1e6f8SHighPoint Linux Team printk(KERN_ERR "hptiop: fail to alloc scsi host\n");
1317ede1e6f8SHighPoint Linux Team goto free_pci_regions;
1318ede1e6f8SHighPoint Linux Team }
1319ede1e6f8SHighPoint Linux Team
1320ede1e6f8SHighPoint Linux Team hba = (struct hptiop_hba *)host->hostdata;
1321a93429c3Slinux memset(hba, 0, sizeof(struct hptiop_hba));
1322ede1e6f8SHighPoint Linux Team
132323f0bb47SHighPoint Linux Team hba->ops = iop_ops;
1324ede1e6f8SHighPoint Linux Team hba->pcidev = pcidev;
1325ede1e6f8SHighPoint Linux Team hba->host = host;
1326ede1e6f8SHighPoint Linux Team hba->initialized = 0;
1327db9b6e89SHighPoint Linux Team hba->iopintf_v2 = 0;
1328ede1e6f8SHighPoint Linux Team
1329ede1e6f8SHighPoint Linux Team atomic_set(&hba->resetting, 0);
1330ede1e6f8SHighPoint Linux Team atomic_set(&hba->reset_count, 0);
1331ede1e6f8SHighPoint Linux Team
1332ede1e6f8SHighPoint Linux Team init_waitqueue_head(&hba->reset_wq);
1333ede1e6f8SHighPoint Linux Team init_waitqueue_head(&hba->ioctl_wq);
1334ede1e6f8SHighPoint Linux Team
1335a93429c3Slinux host->max_lun = 128;
1336ede1e6f8SHighPoint Linux Team host->max_channel = 0;
1337ede1e6f8SHighPoint Linux Team host->io_port = 0;
1338ede1e6f8SHighPoint Linux Team host->n_io_port = 0;
1339ede1e6f8SHighPoint Linux Team host->irq = pcidev->irq;
1340ede1e6f8SHighPoint Linux Team
134100f59701SHighPoint Linux Team if (hba->ops->map_pci_bar(hba))
1342ede1e6f8SHighPoint Linux Team goto free_scsi_host;
1343ede1e6f8SHighPoint Linux Team
134400f59701SHighPoint Linux Team if (hba->ops->iop_wait_ready(hba, 20000)) {
1345ede1e6f8SHighPoint Linux Team printk(KERN_ERR "scsi%d: firmware not ready\n",
1346ede1e6f8SHighPoint Linux Team hba->host->host_no);
1347ede1e6f8SHighPoint Linux Team goto unmap_pci_bar;
1348ede1e6f8SHighPoint Linux Team }
1349ede1e6f8SHighPoint Linux Team
1350286aa031SHighPoint Linux Team if (hba->ops->family == MV_BASED_IOP) {
135100f59701SHighPoint Linux Team if (hba->ops->internal_memalloc(hba)) {
135200f59701SHighPoint Linux Team printk(KERN_ERR "scsi%d: internal_memalloc failed\n",
135300f59701SHighPoint Linux Team hba->host->host_no);
135400f59701SHighPoint Linux Team goto unmap_pci_bar;
135500f59701SHighPoint Linux Team }
135600f59701SHighPoint Linux Team }
135700f59701SHighPoint Linux Team
135800f59701SHighPoint Linux Team if (hba->ops->get_config(hba, &iop_config)) {
1359ede1e6f8SHighPoint Linux Team printk(KERN_ERR "scsi%d: get config failed\n",
1360ede1e6f8SHighPoint Linux Team hba->host->host_no);
1361ede1e6f8SHighPoint Linux Team goto unmap_pci_bar;
1362ede1e6f8SHighPoint Linux Team }
1363ede1e6f8SHighPoint Linux Team
1364ede1e6f8SHighPoint Linux Team hba->max_requests = min(le32_to_cpu(iop_config.max_requests),
1365ede1e6f8SHighPoint Linux Team HPTIOP_MAX_REQUESTS);
1366ede1e6f8SHighPoint Linux Team hba->max_devices = le32_to_cpu(iop_config.max_devices);
1367ede1e6f8SHighPoint Linux Team hba->max_request_size = le32_to_cpu(iop_config.request_size);
1368ede1e6f8SHighPoint Linux Team hba->max_sg_descriptors = le32_to_cpu(iop_config.max_sg_count);
1369ede1e6f8SHighPoint Linux Team hba->firmware_version = le32_to_cpu(iop_config.firmware_version);
1370db9b6e89SHighPoint Linux Team hba->interface_version = le32_to_cpu(iop_config.interface_version);
1371ede1e6f8SHighPoint Linux Team hba->sdram_size = le32_to_cpu(iop_config.sdram_size);
1372ede1e6f8SHighPoint Linux Team
1373286aa031SHighPoint Linux Team if (hba->ops->family == MVFREY_BASED_IOP) {
1374286aa031SHighPoint Linux Team if (hba->ops->internal_memalloc(hba)) {
1375286aa031SHighPoint Linux Team printk(KERN_ERR "scsi%d: internal_memalloc failed\n",
1376286aa031SHighPoint Linux Team hba->host->host_no);
1377286aa031SHighPoint Linux Team goto unmap_pci_bar;
1378286aa031SHighPoint Linux Team }
1379286aa031SHighPoint Linux Team if (hba->ops->reset_comm(hba)) {
1380286aa031SHighPoint Linux Team printk(KERN_ERR "scsi%d: reset comm failed\n",
1381286aa031SHighPoint Linux Team hba->host->host_no);
1382286aa031SHighPoint Linux Team goto unmap_pci_bar;
1383286aa031SHighPoint Linux Team }
1384286aa031SHighPoint Linux Team }
1385286aa031SHighPoint Linux Team
1386db9b6e89SHighPoint Linux Team if (hba->firmware_version > 0x01020000 ||
1387db9b6e89SHighPoint Linux Team hba->interface_version > 0x01020000)
1388db9b6e89SHighPoint Linux Team hba->iopintf_v2 = 1;
1389db9b6e89SHighPoint Linux Team
1390ede1e6f8SHighPoint Linux Team host->max_sectors = le32_to_cpu(iop_config.data_transfer_length) >> 9;
1391ede1e6f8SHighPoint Linux Team host->max_id = le32_to_cpu(iop_config.max_devices);
1392ede1e6f8SHighPoint Linux Team host->sg_tablesize = le32_to_cpu(iop_config.max_sg_count);
1393ede1e6f8SHighPoint Linux Team host->can_queue = le32_to_cpu(iop_config.max_requests);
1394ede1e6f8SHighPoint Linux Team host->cmd_per_lun = le32_to_cpu(iop_config.max_requests);
1395ede1e6f8SHighPoint Linux Team host->max_cmd_len = 16;
1396ede1e6f8SHighPoint Linux Team
13975b12a568SGustavo A. R. Silva req_size = struct_size_t(struct hpt_iop_request_scsi_command,
13985b12a568SGustavo A. R. Silva sg_list, hba->max_sg_descriptors);
1399db9b6e89SHighPoint Linux Team if ((req_size & 0x1f) != 0)
1400db9b6e89SHighPoint Linux Team req_size = (req_size + 0x1f) & ~0x1f;
1401db9b6e89SHighPoint Linux Team
1402db9b6e89SHighPoint Linux Team memset(&set_config, 0, sizeof(struct hpt_iop_request_set_config));
1403ede1e6f8SHighPoint Linux Team set_config.iop_id = cpu_to_le32(host->host_no);
1404db9b6e89SHighPoint Linux Team set_config.vbus_id = cpu_to_le16(host->host_no);
1405db9b6e89SHighPoint Linux Team set_config.max_host_request_size = cpu_to_le16(req_size);
1406ede1e6f8SHighPoint Linux Team
140700f59701SHighPoint Linux Team if (hba->ops->set_config(hba, &set_config)) {
1408ede1e6f8SHighPoint Linux Team printk(KERN_ERR "scsi%d: set config failed\n",
1409ede1e6f8SHighPoint Linux Team hba->host->host_no);
1410ede1e6f8SHighPoint Linux Team goto unmap_pci_bar;
1411ede1e6f8SHighPoint Linux Team }
1412ede1e6f8SHighPoint Linux Team
1413ede1e6f8SHighPoint Linux Team pci_set_drvdata(pcidev, host);
1414ede1e6f8SHighPoint Linux Team
14151d6f359aSThomas Gleixner if (request_irq(pcidev->irq, hptiop_intr, IRQF_SHARED,
1416ede1e6f8SHighPoint Linux Team driver_name, hba)) {
1417ede1e6f8SHighPoint Linux Team printk(KERN_ERR "scsi%d: request irq %d failed\n",
1418ede1e6f8SHighPoint Linux Team hba->host->host_no, pcidev->irq);
14193e74051bSChristoph Hellwig goto unmap_pci_bar;
1420ede1e6f8SHighPoint Linux Team }
1421ede1e6f8SHighPoint Linux Team
1422ede1e6f8SHighPoint Linux Team /* Allocate request mem */
1423ede1e6f8SHighPoint Linux Team
1424ede1e6f8SHighPoint Linux Team dprintk("req_size=%d, max_requests=%d\n", req_size, hba->max_requests);
1425ede1e6f8SHighPoint Linux Team
1426ede1e6f8SHighPoint Linux Team hba->req_size = req_size;
1427a93429c3Slinux hba->req_list = NULL;
1428a93429c3Slinux
1429a93429c3Slinux for (i = 0; i < hba->max_requests; i++) {
1430ede1e6f8SHighPoint Linux Team start_virt = dma_alloc_coherent(&pcidev->dev,
1431a93429c3Slinux hba->req_size + 0x20,
1432ede1e6f8SHighPoint Linux Team &start_phy, GFP_KERNEL);
1433ede1e6f8SHighPoint Linux Team
1434ede1e6f8SHighPoint Linux Team if (!start_virt) {
1435ede1e6f8SHighPoint Linux Team printk(KERN_ERR "scsi%d: fail to alloc request mem\n",
1436ede1e6f8SHighPoint Linux Team hba->host->host_no);
1437a93429c3Slinux goto free_request_mem;
1438ede1e6f8SHighPoint Linux Team }
1439ede1e6f8SHighPoint Linux Team
1440a93429c3Slinux hba->dma_coherent[i] = start_virt;
1441a93429c3Slinux hba->dma_coherent_handle[i] = start_phy;
1442ede1e6f8SHighPoint Linux Team
1443286aa031SHighPoint Linux Team if ((start_phy & 0x1f) != 0) {
1444ede1e6f8SHighPoint Linux Team offset = ((start_phy + 0x1f) & ~0x1f) - start_phy;
1445ede1e6f8SHighPoint Linux Team start_phy += offset;
1446ede1e6f8SHighPoint Linux Team start_virt += offset;
1447ede1e6f8SHighPoint Linux Team }
1448ede1e6f8SHighPoint Linux Team
1449ede1e6f8SHighPoint Linux Team hba->reqs[i].next = NULL;
1450ede1e6f8SHighPoint Linux Team hba->reqs[i].req_virt = start_virt;
1451ede1e6f8SHighPoint Linux Team hba->reqs[i].req_shifted_phy = start_phy >> 5;
1452ede1e6f8SHighPoint Linux Team hba->reqs[i].index = i;
1453ede1e6f8SHighPoint Linux Team free_req(hba, &hba->reqs[i]);
1454ede1e6f8SHighPoint Linux Team }
1455ede1e6f8SHighPoint Linux Team
1456ede1e6f8SHighPoint Linux Team /* Enable Interrupt and start background task */
1457ede1e6f8SHighPoint Linux Team if (hptiop_initialize_iop(hba))
1458ede1e6f8SHighPoint Linux Team goto free_request_mem;
1459ede1e6f8SHighPoint Linux Team
14603e74051bSChristoph Hellwig if (scsi_add_host(host, &pcidev->dev)) {
14613e74051bSChristoph Hellwig printk(KERN_ERR "scsi%d: scsi_add_host failed\n",
14623e74051bSChristoph Hellwig hba->host->host_no);
14633e74051bSChristoph Hellwig goto free_request_mem;
14643e74051bSChristoph Hellwig }
14653e74051bSChristoph Hellwig
1466ede1e6f8SHighPoint Linux Team scsi_scan_host(host);
1467ede1e6f8SHighPoint Linux Team
1468ede1e6f8SHighPoint Linux Team dprintk("scsi%d: hptiop_probe successfully\n", hba->host->host_no);
1469ede1e6f8SHighPoint Linux Team return 0;
1470ede1e6f8SHighPoint Linux Team
1471ede1e6f8SHighPoint Linux Team free_request_mem:
1472a93429c3Slinux for (i = 0; i < hba->max_requests; i++) {
1473a93429c3Slinux if (hba->dma_coherent[i] && hba->dma_coherent_handle[i])
1474ede1e6f8SHighPoint Linux Team dma_free_coherent(&hba->pcidev->dev,
1475a93429c3Slinux hba->req_size + 0x20,
1476a93429c3Slinux hba->dma_coherent[i],
1477a93429c3Slinux hba->dma_coherent_handle[i]);
1478a93429c3Slinux else
1479a93429c3Slinux break;
1480a93429c3Slinux }
1481ede1e6f8SHighPoint Linux Team
1482ede1e6f8SHighPoint Linux Team free_irq(hba->pcidev->irq, hba);
1483ede1e6f8SHighPoint Linux Team
1484ede1e6f8SHighPoint Linux Team unmap_pci_bar:
148500f59701SHighPoint Linux Team hba->ops->internal_memfree(hba);
1486ede1e6f8SHighPoint Linux Team
148700f59701SHighPoint Linux Team hba->ops->unmap_pci_bar(hba);
1488ede1e6f8SHighPoint Linux Team
1489ede1e6f8SHighPoint Linux Team free_scsi_host:
1490ede1e6f8SHighPoint Linux Team scsi_host_put(host);
1491ede1e6f8SHighPoint Linux Team
149200f59701SHighPoint Linux Team free_pci_regions:
149300f59701SHighPoint Linux Team pci_release_regions(pcidev);
149400f59701SHighPoint Linux Team
1495ede1e6f8SHighPoint Linux Team disable_pci_device:
1496ede1e6f8SHighPoint Linux Team pci_disable_device(pcidev);
1497ede1e6f8SHighPoint Linux Team
14981db90ea2SJulia Lawall dprintk("scsi%d: hptiop_probe fail\n", host ? host->host_no : 0);
1499ede1e6f8SHighPoint Linux Team return -ENODEV;
1500ede1e6f8SHighPoint Linux Team }
1501ede1e6f8SHighPoint Linux Team
hptiop_shutdown(struct pci_dev * pcidev)1502ede1e6f8SHighPoint Linux Team static void hptiop_shutdown(struct pci_dev *pcidev)
1503ede1e6f8SHighPoint Linux Team {
1504ede1e6f8SHighPoint Linux Team struct Scsi_Host *host = pci_get_drvdata(pcidev);
1505ede1e6f8SHighPoint Linux Team struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
1506ede1e6f8SHighPoint Linux Team
1507ede1e6f8SHighPoint Linux Team dprintk("hptiop_shutdown(%p)\n", hba);
1508ede1e6f8SHighPoint Linux Team
1509ede1e6f8SHighPoint Linux Team /* stop the iop */
1510ede1e6f8SHighPoint Linux Team if (iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_SHUTDOWN, 60000))
1511ede1e6f8SHighPoint Linux Team printk(KERN_ERR "scsi%d: shutdown the iop timeout\n",
1512ede1e6f8SHighPoint Linux Team hba->host->host_no);
1513ede1e6f8SHighPoint Linux Team
1514ede1e6f8SHighPoint Linux Team /* disable all outbound interrupts */
151500f59701SHighPoint Linux Team hba->ops->disable_intr(hba);
151600f59701SHighPoint Linux Team }
151700f59701SHighPoint Linux Team
hptiop_disable_intr_itl(struct hptiop_hba * hba)151800f59701SHighPoint Linux Team static void hptiop_disable_intr_itl(struct hptiop_hba *hba)
151900f59701SHighPoint Linux Team {
152000f59701SHighPoint Linux Team u32 int_mask;
152100f59701SHighPoint Linux Team
152200f59701SHighPoint Linux Team int_mask = readl(&hba->u.itl.iop->outbound_intmask);
1523ede1e6f8SHighPoint Linux Team writel(int_mask |
1524ede1e6f8SHighPoint Linux Team IOPMU_OUTBOUND_INT_MSG0 | IOPMU_OUTBOUND_INT_POSTQUEUE,
152500f59701SHighPoint Linux Team &hba->u.itl.iop->outbound_intmask);
152600f59701SHighPoint Linux Team readl(&hba->u.itl.iop->outbound_intmask);
152700f59701SHighPoint Linux Team }
152800f59701SHighPoint Linux Team
hptiop_disable_intr_mv(struct hptiop_hba * hba)152900f59701SHighPoint Linux Team static void hptiop_disable_intr_mv(struct hptiop_hba *hba)
153000f59701SHighPoint Linux Team {
153100f59701SHighPoint Linux Team writel(0, &hba->u.mv.regs->outbound_intmask);
153200f59701SHighPoint Linux Team readl(&hba->u.mv.regs->outbound_intmask);
1533ede1e6f8SHighPoint Linux Team }
1534ede1e6f8SHighPoint Linux Team
hptiop_disable_intr_mvfrey(struct hptiop_hba * hba)1535286aa031SHighPoint Linux Team static void hptiop_disable_intr_mvfrey(struct hptiop_hba *hba)
1536286aa031SHighPoint Linux Team {
1537286aa031SHighPoint Linux Team writel(0, &(hba->u.mvfrey.mu->f0_doorbell_enable));
1538286aa031SHighPoint Linux Team readl(&(hba->u.mvfrey.mu->f0_doorbell_enable));
1539286aa031SHighPoint Linux Team writel(0, &(hba->u.mvfrey.mu->isr_enable));
1540286aa031SHighPoint Linux Team readl(&(hba->u.mvfrey.mu->isr_enable));
1541286aa031SHighPoint Linux Team writel(0, &(hba->u.mvfrey.mu->pcie_f0_int_enable));
1542286aa031SHighPoint Linux Team readl(&(hba->u.mvfrey.mu->pcie_f0_int_enable));
1543286aa031SHighPoint Linux Team }
1544286aa031SHighPoint Linux Team
hptiop_remove(struct pci_dev * pcidev)1545ede1e6f8SHighPoint Linux Team static void hptiop_remove(struct pci_dev *pcidev)
1546ede1e6f8SHighPoint Linux Team {
1547ede1e6f8SHighPoint Linux Team struct Scsi_Host *host = pci_get_drvdata(pcidev);
1548ede1e6f8SHighPoint Linux Team struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
1549a93429c3Slinux u32 i;
1550ede1e6f8SHighPoint Linux Team
1551ede1e6f8SHighPoint Linux Team dprintk("scsi%d: hptiop_remove\n", hba->host->host_no);
1552ede1e6f8SHighPoint Linux Team
15534f2ddba3SHighPoint Linux Team scsi_remove_host(host);
15544f2ddba3SHighPoint Linux Team
1555ede1e6f8SHighPoint Linux Team hptiop_shutdown(pcidev);
1556ede1e6f8SHighPoint Linux Team
1557ede1e6f8SHighPoint Linux Team free_irq(hba->pcidev->irq, hba);
1558ede1e6f8SHighPoint Linux Team
1559a93429c3Slinux for (i = 0; i < hba->max_requests; i++) {
1560a93429c3Slinux if (hba->dma_coherent[i] && hba->dma_coherent_handle[i])
1561ede1e6f8SHighPoint Linux Team dma_free_coherent(&hba->pcidev->dev,
1562a93429c3Slinux hba->req_size + 0x20,
1563a93429c3Slinux hba->dma_coherent[i],
1564a93429c3Slinux hba->dma_coherent_handle[i]);
1565a93429c3Slinux else
1566a93429c3Slinux break;
1567a93429c3Slinux }
1568ede1e6f8SHighPoint Linux Team
156900f59701SHighPoint Linux Team hba->ops->internal_memfree(hba);
157000f59701SHighPoint Linux Team
157100f59701SHighPoint Linux Team hba->ops->unmap_pci_bar(hba);
1572ede1e6f8SHighPoint Linux Team
1573ede1e6f8SHighPoint Linux Team pci_release_regions(hba->pcidev);
1574ede1e6f8SHighPoint Linux Team pci_set_drvdata(hba->pcidev, NULL);
1575ede1e6f8SHighPoint Linux Team pci_disable_device(hba->pcidev);
1576ede1e6f8SHighPoint Linux Team
1577ede1e6f8SHighPoint Linux Team scsi_host_put(host);
1578ede1e6f8SHighPoint Linux Team }
1579ede1e6f8SHighPoint Linux Team
158000f59701SHighPoint Linux Team static struct hptiop_adapter_ops hptiop_itl_ops = {
1581286aa031SHighPoint Linux Team .family = INTEL_BASED_IOP,
158200f59701SHighPoint Linux Team .iop_wait_ready = iop_wait_ready_itl,
1583286aa031SHighPoint Linux Team .internal_memalloc = hptiop_internal_memalloc_itl,
1584286aa031SHighPoint Linux Team .internal_memfree = hptiop_internal_memfree_itl,
158500f59701SHighPoint Linux Team .map_pci_bar = hptiop_map_pci_bar_itl,
158600f59701SHighPoint Linux Team .unmap_pci_bar = hptiop_unmap_pci_bar_itl,
158700f59701SHighPoint Linux Team .enable_intr = hptiop_enable_intr_itl,
158800f59701SHighPoint Linux Team .disable_intr = hptiop_disable_intr_itl,
158900f59701SHighPoint Linux Team .get_config = iop_get_config_itl,
159000f59701SHighPoint Linux Team .set_config = iop_set_config_itl,
159100f59701SHighPoint Linux Team .iop_intr = iop_intr_itl,
159200f59701SHighPoint Linux Team .post_msg = hptiop_post_msg_itl,
159300f59701SHighPoint Linux Team .post_req = hptiop_post_req_itl,
159423f0bb47SHighPoint Linux Team .hw_dma_bit_mask = 64,
1595286aa031SHighPoint Linux Team .reset_comm = hptiop_reset_comm_itl,
1596286aa031SHighPoint Linux Team .host_phy_flag = cpu_to_le64(0),
159700f59701SHighPoint Linux Team };
159800f59701SHighPoint Linux Team
159900f59701SHighPoint Linux Team static struct hptiop_adapter_ops hptiop_mv_ops = {
1600286aa031SHighPoint Linux Team .family = MV_BASED_IOP,
160100f59701SHighPoint Linux Team .iop_wait_ready = iop_wait_ready_mv,
160200f59701SHighPoint Linux Team .internal_memalloc = hptiop_internal_memalloc_mv,
160300f59701SHighPoint Linux Team .internal_memfree = hptiop_internal_memfree_mv,
160400f59701SHighPoint Linux Team .map_pci_bar = hptiop_map_pci_bar_mv,
160500f59701SHighPoint Linux Team .unmap_pci_bar = hptiop_unmap_pci_bar_mv,
160600f59701SHighPoint Linux Team .enable_intr = hptiop_enable_intr_mv,
160700f59701SHighPoint Linux Team .disable_intr = hptiop_disable_intr_mv,
160800f59701SHighPoint Linux Team .get_config = iop_get_config_mv,
160900f59701SHighPoint Linux Team .set_config = iop_set_config_mv,
161000f59701SHighPoint Linux Team .iop_intr = iop_intr_mv,
161100f59701SHighPoint Linux Team .post_msg = hptiop_post_msg_mv,
161200f59701SHighPoint Linux Team .post_req = hptiop_post_req_mv,
161323f0bb47SHighPoint Linux Team .hw_dma_bit_mask = 33,
1614286aa031SHighPoint Linux Team .reset_comm = hptiop_reset_comm_mv,
1615286aa031SHighPoint Linux Team .host_phy_flag = cpu_to_le64(0),
1616286aa031SHighPoint Linux Team };
1617286aa031SHighPoint Linux Team
1618286aa031SHighPoint Linux Team static struct hptiop_adapter_ops hptiop_mvfrey_ops = {
1619286aa031SHighPoint Linux Team .family = MVFREY_BASED_IOP,
1620286aa031SHighPoint Linux Team .iop_wait_ready = iop_wait_ready_mvfrey,
1621286aa031SHighPoint Linux Team .internal_memalloc = hptiop_internal_memalloc_mvfrey,
1622286aa031SHighPoint Linux Team .internal_memfree = hptiop_internal_memfree_mvfrey,
1623286aa031SHighPoint Linux Team .map_pci_bar = hptiop_map_pci_bar_mvfrey,
1624286aa031SHighPoint Linux Team .unmap_pci_bar = hptiop_unmap_pci_bar_mvfrey,
1625286aa031SHighPoint Linux Team .enable_intr = hptiop_enable_intr_mvfrey,
1626286aa031SHighPoint Linux Team .disable_intr = hptiop_disable_intr_mvfrey,
1627286aa031SHighPoint Linux Team .get_config = iop_get_config_mvfrey,
1628286aa031SHighPoint Linux Team .set_config = iop_set_config_mvfrey,
1629286aa031SHighPoint Linux Team .iop_intr = iop_intr_mvfrey,
1630286aa031SHighPoint Linux Team .post_msg = hptiop_post_msg_mvfrey,
1631286aa031SHighPoint Linux Team .post_req = hptiop_post_req_mvfrey,
1632286aa031SHighPoint Linux Team .hw_dma_bit_mask = 64,
1633286aa031SHighPoint Linux Team .reset_comm = hptiop_reset_comm_mvfrey,
1634286aa031SHighPoint Linux Team .host_phy_flag = cpu_to_le64(1),
163500f59701SHighPoint Linux Team };
163600f59701SHighPoint Linux Team
1637ede1e6f8SHighPoint Linux Team static struct pci_device_id hptiop_id_table[] = {
163800f59701SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x3220), (kernel_ulong_t)&hptiop_itl_ops },
163900f59701SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x3320), (kernel_ulong_t)&hptiop_itl_ops },
16403bfc13c2SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x3410), (kernel_ulong_t)&hptiop_itl_ops },
164100f59701SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x3510), (kernel_ulong_t)&hptiop_itl_ops },
164200f59701SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x3511), (kernel_ulong_t)&hptiop_itl_ops },
16433bfc13c2SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x3520), (kernel_ulong_t)&hptiop_itl_ops },
164400f59701SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x3521), (kernel_ulong_t)&hptiop_itl_ops },
164500f59701SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x3522), (kernel_ulong_t)&hptiop_itl_ops },
1646dd07428bSHighPoint Linux Team { PCI_VDEVICE(TTI, 0x3530), (kernel_ulong_t)&hptiop_itl_ops },
16473bfc13c2SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x3540), (kernel_ulong_t)&hptiop_itl_ops },
1648dd07428bSHighPoint Linux Team { PCI_VDEVICE(TTI, 0x3560), (kernel_ulong_t)&hptiop_itl_ops },
1649dd07428bSHighPoint Linux Team { PCI_VDEVICE(TTI, 0x4210), (kernel_ulong_t)&hptiop_itl_ops },
1650dd07428bSHighPoint Linux Team { PCI_VDEVICE(TTI, 0x4211), (kernel_ulong_t)&hptiop_itl_ops },
1651dd07428bSHighPoint Linux Team { PCI_VDEVICE(TTI, 0x4310), (kernel_ulong_t)&hptiop_itl_ops },
1652dd07428bSHighPoint Linux Team { PCI_VDEVICE(TTI, 0x4311), (kernel_ulong_t)&hptiop_itl_ops },
16533bfc13c2SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x4320), (kernel_ulong_t)&hptiop_itl_ops },
16543bfc13c2SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x4321), (kernel_ulong_t)&hptiop_itl_ops },
16553bfc13c2SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x4322), (kernel_ulong_t)&hptiop_itl_ops },
16563bfc13c2SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x4400), (kernel_ulong_t)&hptiop_itl_ops },
165700f59701SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x3120), (kernel_ulong_t)&hptiop_mv_ops },
165800f59701SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x3122), (kernel_ulong_t)&hptiop_mv_ops },
165900f59701SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x3020), (kernel_ulong_t)&hptiop_mv_ops },
1660286aa031SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x4520), (kernel_ulong_t)&hptiop_mvfrey_ops },
1661286aa031SHighPoint Linux Team { PCI_VDEVICE(TTI, 0x4522), (kernel_ulong_t)&hptiop_mvfrey_ops },
1662a93429c3Slinux { PCI_VDEVICE(TTI, 0x3610), (kernel_ulong_t)&hptiop_mvfrey_ops },
1663a93429c3Slinux { PCI_VDEVICE(TTI, 0x3611), (kernel_ulong_t)&hptiop_mvfrey_ops },
1664a93429c3Slinux { PCI_VDEVICE(TTI, 0x3620), (kernel_ulong_t)&hptiop_mvfrey_ops },
1665a93429c3Slinux { PCI_VDEVICE(TTI, 0x3622), (kernel_ulong_t)&hptiop_mvfrey_ops },
1666a93429c3Slinux { PCI_VDEVICE(TTI, 0x3640), (kernel_ulong_t)&hptiop_mvfrey_ops },
1667a93429c3Slinux { PCI_VDEVICE(TTI, 0x3660), (kernel_ulong_t)&hptiop_mvfrey_ops },
1668a93429c3Slinux { PCI_VDEVICE(TTI, 0x3680), (kernel_ulong_t)&hptiop_mvfrey_ops },
1669a93429c3Slinux { PCI_VDEVICE(TTI, 0x3690), (kernel_ulong_t)&hptiop_mvfrey_ops },
1670ede1e6f8SHighPoint Linux Team {},
1671ede1e6f8SHighPoint Linux Team };
1672ede1e6f8SHighPoint Linux Team
1673ede1e6f8SHighPoint Linux Team MODULE_DEVICE_TABLE(pci, hptiop_id_table);
1674ede1e6f8SHighPoint Linux Team
1675ede1e6f8SHighPoint Linux Team static struct pci_driver hptiop_pci_driver = {
1676ede1e6f8SHighPoint Linux Team .name = driver_name,
1677ede1e6f8SHighPoint Linux Team .id_table = hptiop_id_table,
1678ede1e6f8SHighPoint Linux Team .probe = hptiop_probe,
1679ede1e6f8SHighPoint Linux Team .remove = hptiop_remove,
1680ede1e6f8SHighPoint Linux Team .shutdown = hptiop_shutdown,
1681ede1e6f8SHighPoint Linux Team };
1682ede1e6f8SHighPoint Linux Team
hptiop_module_init(void)1683ede1e6f8SHighPoint Linux Team static int __init hptiop_module_init(void)
1684ede1e6f8SHighPoint Linux Team {
1685ede1e6f8SHighPoint Linux Team printk(KERN_INFO "%s %s\n", driver_name_long, driver_ver);
16863e74051bSChristoph Hellwig return pci_register_driver(&hptiop_pci_driver);
1687ede1e6f8SHighPoint Linux Team }
1688ede1e6f8SHighPoint Linux Team
hptiop_module_exit(void)1689ede1e6f8SHighPoint Linux Team static void __exit hptiop_module_exit(void)
1690ede1e6f8SHighPoint Linux Team {
1691ede1e6f8SHighPoint Linux Team pci_unregister_driver(&hptiop_pci_driver);
1692ede1e6f8SHighPoint Linux Team }
1693ede1e6f8SHighPoint Linux Team
1694ede1e6f8SHighPoint Linux Team
1695ede1e6f8SHighPoint Linux Team module_init(hptiop_module_init);
1696ede1e6f8SHighPoint Linux Team module_exit(hptiop_module_exit);
1697ede1e6f8SHighPoint Linux Team
1698ede1e6f8SHighPoint Linux Team MODULE_LICENSE("GPL");
1699db9b6e89SHighPoint Linux Team
1700