arcmsr_hba.c
来自「linux 内核源代码」· C语言 代码 · 共 2,271 行 · 第 1/5 页
C
2,271 行
/********************************************************************************** O.S : Linux** FILE NAME : arcmsr_hba.c** BY : Erich Chen** Description: SCSI RAID Device Driver for** ARECA RAID Host adapter********************************************************************************* Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved**** Web site: www.areca.com.tw** E-mail: support@areca.com.tw**** This program is free software; you can redistribute it and/or modify** it under the terms of the GNU General Public License version 2 as** published by the Free Software Foundation.** This program is distributed in the hope that it will be useful,** but WITHOUT ANY WARRANTY; without even the implied warranty of** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the** GNU General Public License for more details.********************************************************************************* Redistribution and use in source and binary forms, with or without** modification, are permitted provided that the following conditions** are met:** 1. Redistributions of source code must retain the above copyright** notice, this list of conditions and the following disclaimer.** 2. Redistributions in binary form must reproduce the above copyright** notice, this list of conditions and the following disclaimer in the** documentation and/or other materials provided with the distribution.** 3. The name of the author may not be used to endorse or promote products** derived from this software without specific prior written permission.**** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING,BUT** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT** (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.********************************************************************************* For history of changes, see Documentation/scsi/ChangeLog.arcmsr** Firmware Specification, see Documentation/scsi/arcmsr_spec.txt********************************************************************************/#include <linux/module.h>#include <linux/reboot.h>#include <linux/spinlock.h>#include <linux/pci_ids.h>#include <linux/interrupt.h>#include <linux/moduleparam.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/delay.h>#include <linux/dma-mapping.h>#include <linux/timer.h>#include <linux/pci.h>#include <linux/aer.h>#include <asm/dma.h>#include <asm/io.h>#include <asm/system.h>#include <asm/uaccess.h>#include <scsi/scsi_host.h>#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_tcq.h>#include <scsi/scsi_device.h>#include <scsi/scsi_transport.h>#include <scsi/scsicam.h>#include "arcmsr.h"MODULE_AUTHOR("Erich Chen <support@areca.com.tw>");MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID HOST Adapter");MODULE_LICENSE("Dual BSD/GPL");MODULE_VERSION(ARCMSR_DRIVER_VERSION);static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd);static int arcmsr_iop_confirm(struct AdapterControlBlock *acb);static int arcmsr_abort(struct scsi_cmnd *);static int arcmsr_bus_reset(struct scsi_cmnd *);static int arcmsr_bios_param(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *info);static int arcmsr_queue_command(struct scsi_cmnd *cmd, void (*done) (struct scsi_cmnd *));static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id);static void arcmsr_remove(struct pci_dev *pdev);static void arcmsr_shutdown(struct pci_dev *pdev);static void arcmsr_iop_init(struct AdapterControlBlock *acb);static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb);static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb);static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb);static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb);static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb);static const char *arcmsr_info(struct Scsi_Host *);static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth){ if (queue_depth > ARCMSR_MAX_CMD_PERLUN) queue_depth = ARCMSR_MAX_CMD_PERLUN; scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); return queue_depth;}static struct scsi_host_template arcmsr_scsi_host_template = { .module = THIS_MODULE, .name = "ARCMSR ARECA SATA/SAS RAID HOST Adapter" ARCMSR_DRIVER_VERSION, .info = arcmsr_info, .queuecommand = arcmsr_queue_command, .eh_abort_handler = arcmsr_abort, .eh_bus_reset_handler = arcmsr_bus_reset, .bios_param = arcmsr_bios_param, .change_queue_depth = arcmsr_adjust_disk_queue_depth, .can_queue = ARCMSR_MAX_OUTSTANDING_CMD, .this_id = ARCMSR_SCSI_INITIATOR_ID, .sg_tablesize = ARCMSR_MAX_SG_ENTRIES, .max_sectors = ARCMSR_MAX_XFER_SECTORS, .cmd_per_lun = ARCMSR_MAX_CMD_PERLUN, .use_clustering = ENABLE_CLUSTERING, .use_sg_chaining = ENABLE_SG_CHAINING, .shost_attrs = arcmsr_host_attrs,};#ifdef CONFIG_SCSI_ARCMSR_AERstatic pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev);static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state);static struct pci_error_handlers arcmsr_pci_error_handlers = { .error_detected = arcmsr_pci_error_detected, .slot_reset = arcmsr_pci_slot_reset,};#endifstatic struct pci_device_id arcmsr_device_id_table[] = { {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1200)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1201)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1260)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1270)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1280)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1380)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681)}, {0, 0}, /* Terminating entry */};MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table);static struct pci_driver arcmsr_pci_driver = { .name = "arcmsr", .id_table = arcmsr_device_id_table, .probe = arcmsr_probe, .remove = arcmsr_remove, .shutdown = arcmsr_shutdown, #ifdef CONFIG_SCSI_ARCMSR_AER .err_handler = &arcmsr_pci_error_handlers, #endif};static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id){ irqreturn_t handle_state; struct AdapterControlBlock *acb = dev_id; spin_lock(acb->host->host_lock); handle_state = arcmsr_interrupt(acb); spin_unlock(acb->host->host_lock); return handle_state;}static int arcmsr_bios_param(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *geom){ int ret, heads, sectors, cylinders, total_capacity; unsigned char *buffer;/* return copy of block device's partition table */ buffer = scsi_bios_ptable(bdev); if (buffer) { ret = scsi_partsize(buffer, capacity, &geom[2], &geom[0], &geom[1]); kfree(buffer); if (ret != -1) return ret; } total_capacity = capacity; heads = 64; sectors = 32; cylinders = total_capacity / (heads * sectors); if (cylinders > 1024) { heads = 255; sectors = 63; cylinders = total_capacity / (heads * sectors); } geom[0] = heads; geom[1] = sectors; geom[2] = cylinders; return 0;}static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb){ struct pci_dev *pdev = acb->pdev; u16 dev_id; pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id); switch (dev_id) { case 0x1201 : { acb->adapter_type = ACB_ADAPTER_TYPE_B; } break; default : acb->adapter_type = ACB_ADAPTER_TYPE_A; }}static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb){ switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { struct pci_dev *pdev = acb->pdev; void *dma_coherent; dma_addr_t dma_coherent_handle, dma_addr; struct CommandControlBlock *ccb_tmp; uint32_t intmask_org; int i, j; acb->pmuA = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); if (!acb->pmuA) { printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); return -ENOMEM; } dma_coherent = dma_alloc_coherent(&pdev->dev, ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20, &dma_coherent_handle, GFP_KERNEL); if (!dma_coherent) { iounmap(acb->pmuA); return -ENOMEM; } acb->dma_coherent = dma_coherent; acb->dma_coherent_handle = dma_coherent_handle; if (((unsigned long)dma_coherent & 0x1F)) { dma_coherent = dma_coherent + (0x20 - ((unsigned long)dma_coherent & 0x1F)); dma_coherent_handle = dma_coherent_handle + (0x20 - ((unsigned long)dma_coherent_handle & 0x1F)); } dma_addr = dma_coherent_handle; ccb_tmp = (struct CommandControlBlock *)dma_coherent; for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5; ccb_tmp->acb = acb; acb->pccb_pool[i] = ccb_tmp; list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); dma_addr = dma_addr + sizeof(struct CommandControlBlock); ccb_tmp++; } acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr; for (i = 0; i < ARCMSR_MAX_TARGETID; i++) for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) acb->devstate[i][j] = ARECA_RAID_GONE; /* ** here we need to tell iop 331 our ccb_tmp.HighPart ** if ccb_tmp.HighPart is not zero */ intmask_org = arcmsr_disable_outbound_ints(acb); } break; case ACB_ADAPTER_TYPE_B: { struct pci_dev *pdev = acb->pdev; struct MessageUnit_B *reg; void __iomem *mem_base0, *mem_base1; void *dma_coherent; dma_addr_t dma_coherent_handle, dma_addr; uint32_t intmask_org; struct CommandControlBlock *ccb_tmp; int i, j; dma_coherent = dma_alloc_coherent(&pdev->dev, ((ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20) + sizeof(struct MessageUnit_B)), &dma_coherent_handle, GFP_KERNEL); if (!dma_coherent) return -ENOMEM; acb->dma_coherent = dma_coherent; acb->dma_coherent_handle = dma_coherent_handle; if (((unsigned long)dma_coherent & 0x1F)) { dma_coherent = dma_coherent + (0x20 - ((unsigned long)dma_coherent & 0x1F)); dma_coherent_handle = dma_coherent_handle + (0x20 - ((unsigned long)dma_coherent_handle & 0x1F)); } reg = (struct MessageUnit_B *)(dma_coherent + ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock)); dma_addr = dma_coherent_handle; ccb_tmp = (struct CommandControlBlock *)dma_coherent; for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5; ccb_tmp->acb = acb; acb->pccb_pool[i] = ccb_tmp; list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); dma_addr = dma_addr + sizeof(struct CommandControlBlock); ccb_tmp++; } reg = (struct MessageUnit_B *)(dma_coherent + ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock)); acb->pmuB = reg; mem_base0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); if (!mem_base0) goto out; mem_base1 = ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); if (!mem_base1) { iounmap(mem_base0); goto out; } reg->drv2iop_doorbell_reg = mem_base0 + ARCMSR_DRV2IOP_DOORBELL; reg->drv2iop_doorbell_mask_reg = mem_base0 + ARCMSR_DRV2IOP_DOORBELL_MASK; reg->iop2drv_doorbell_reg = mem_base0 + ARCMSR_IOP2DRV_DOORBELL; reg->iop2drv_doorbell_mask_reg = mem_base0 + ARCMSR_IOP2DRV_DOORBELL_MASK; reg->ioctl_wbuffer_reg = mem_base1 + ARCMSR_IOCTL_WBUFFER; reg->ioctl_rbuffer_reg = mem_base1 + ARCMSR_IOCTL_RBUFFER; reg->msgcode_rwbuffer_reg = mem_base1 + ARCMSR_MSGCODE_RWBUFFER; acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr; for (i = 0; i < ARCMSR_MAX_TARGETID; i++) for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) acb->devstate[i][j] = ARECA_RAID_GOOD; /* ** here we need to tell iop 331 our ccb_tmp.HighPart ** if ccb_tmp.HighPart is not zero */ intmask_org = arcmsr_disable_outbound_ints(acb); } break; } return 0;out: dma_free_coherent(&acb->pdev->dev, ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20, acb->dma_coherent, acb->dma_coherent_handle); return -ENOMEM;}static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id){ struct Scsi_Host *host; struct AdapterControlBlock *acb; uint8_t bus, dev_fun; int error; error = pci_enable_device(pdev); if (error) goto out; pci_set_master(pdev); host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof(struct AdapterControlBlock)); if (!host) { error = -ENOMEM; goto out_disable_device; } acb = (struct AdapterControlBlock *)host->hostdata; memset(acb, 0, sizeof (struct AdapterControlBlock)); error = pci_set_dma_mask(pdev, DMA_64BIT_MASK); if (error) { error = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (error) { printk(KERN_WARNING "scsi%d: No suitable DMA mask available\n", host->host_no); goto out_host_put; } } bus = pdev->bus->number; dev_fun = pdev->devfn; acb->host = host; acb->pdev = pdev; host->max_sectors = ARCMSR_MAX_XFER_SECTORS; host->max_lun = ARCMSR_MAX_TARGETLUN; host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/ host->max_cmd_len = 16; /*this is issue of 64bit LBA, over 2T byte*/ host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES; host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */ host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN; host->this_id = ARCMSR_SCSI_INITIATOR_ID; host->unique_id = (bus << 8) | dev_fun; host->irq = pdev->irq; error = pci_request_regions(pdev, "arcmsr"); if (error) { goto out_host_put; } arcmsr_define_adapter_type(acb); acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | ACB_F_MESSAGE_RQBUFFER_CLEARED | ACB_F_MESSAGE_WQBUFFER_READED); acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER; INIT_LIST_HEAD(&acb->ccb_free_list); error = arcmsr_alloc_ccb_pool(acb); if (error) goto out_release_regions; error = request_irq(pdev->irq, arcmsr_do_interrupt, IRQF_SHARED, "arcmsr", acb); if (error) goto out_free_ccb_pool; arcmsr_iop_init(acb); pci_set_drvdata(pdev, host); if (strncmp(acb->firm_version, "V1.42", 5) >= 0) host->max_sectors= ARCMSR_MAX_XFER_SECTORS_B; error = scsi_add_host(host, &pdev->dev); if (error) goto out_free_irq;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?