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