From: Erich Chen This patch removes an unneeded #include. (hch sez: There's lots of architectural problems. It's doing it's own queueing, it's stuffing kernel structures into memory on the hardware and so on. Basically someone knowledgeable about the hardware needs to start from scratch on it. Unfortunately it seems the hardware is more and more widely available so we'll have to bite that bullet one day.) From: Randy Dunlap Many Linux kernel style cleanups. Summary of general issues for this driver: I'm not addressing SCSI or MM/DMA API issues, if there are any. 0. some Kconfig and Makefile cleanups 1. fix arcmsr_device_id_table[] inits; 2. fix return (value); -- don't use parenethese 3. fix one-line-ifs-with-braces -- remove braces 4. struct _XYZ & typedef XYZ, PXYZ -- convert to struct XYZ only 5. check NULL usage, use NULL instead of 0 for pointers 6. no "return;" at end of func; -- removed 7. return -ENXIO instead of ENXIO; 8. don't indent cases in a switch block. 9. don't use // comments; Patch for above items is below. More issues, not yet patched: 10. use printk levels 11. pPCI_DEV: bad naming (throughout driver; don't use mixed case) 12. some comments are unreadable (non-ASCII ?) 13. uintNN_t int types: use kernel types except for userspace interfaces 14. use kernel-doc 15. try to fit source files into 80 columns (lots fixed, lots to go) 16. Tab size in Linux kernel is 8 (not less). 17. Don't put changelog comments in source files. That's what SCMs are for (source code manager tools). 18. Put arcmsr.txt in Documentation/scsi/, not in scsi/arcmsr/. 19. Maybe use sysfs (/sys) instead of /proc. 20. check sparse warnings, stack usage, init/exit sections; (No stack size problems found; some sparse warnings fixed, more to be done.) From: "erich" The arcmsr patch file update2 works for: 1. use printk levels 2. change pPCI_DEV bad naming into pci_device 3. delete some unreadable comments 4. try to fit source files into 80 columns (lots fixed, lots to go) 5. Tab size in Linux kernel is 8 (not less). 6. Put changelog comments in Documentation/scsi/ChangeLog.arcmsr From: Erich Chen 1. add SCSI_ARCMSR_MSI at Kconfig 2. use spaces after ',' 3. add spaces around the '=' sign 4. define sense ErrorCode instead of magic numbers 0x70 5. include linux/dma-mapping.h 6. correct message of "unknow" => "unknown" 7. run sparse on it and fix it with none warning Signed-off-by: Erich Chen From: Christoph Hellwig On Mon, Feb 20, 2006 at 11:02:32AM -0700, Dax Kelson wrote: > This appears to be the most current version of the driver: > > ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.16-rc4/2.6.16-rc4-mm1/broken-out/areca-raid-linux-scsi-driver.patch > > Is this the current TODO list? > > ================= > Issues not yet patched: > > 13. uintNN_t int types: use kernel types except for userspace > interfaces > 14. use kernel-doc > 18. Put arcmsr.txt in Documentation/scsi/, not in scsi/arcmsr/. > 19. Maybe use sysfs (/sys) instead of /proc. > 20. check stack usage, init/exit sections; - remove internal queueing - fix hardware datastructures - remove odd ioctls - remove useless forward prototypes - give types like ACB useful names - give variable useful names, especially follow kernel conventions, e.g. a struct pci_dev is usually named pdev - kill ->proc_info method - use normal comment style even for comments not fitting into the kernel-doc item above. kill useless separator comments without text - convert arcmsr_show_firmware_info to useful one value per file attributes. best follow the schemes used in aacraid or lpfc - convert arcmsr_show_driver_state to useful one value per file attributes. - remove never called release method in the host template - audit whether setting unchecked_isa_dma to false really makes sense (I strongly doubt it) - remove shutdown notifier, add pci_driver ->shutdown method instead - remove CameCase PCI Ids. The vendor Id should go into pci_ids.h, the device ids either removed or spelled the normal linux way - arcmsr_do_interrupt should stop walking the global host list and use the private data passed to request_irq - the global host list should go away completely - arcmsr_bios_param looks like duplicating the generic CAM version? - locking needs to be redone. If the driver really needs more than one per-host lock we'll want a very good explanation - arcmsr_device_probe needs to be rewritten to do goto-based error unwinding. - msi should be a module options if at all, but defintitly not a config options - arcmsr_scsi_host_template_init should go away. the host template must be initialized statically with no run-time writes to it - the hardware documentation should be split out of arcmsr.h into a separate file (btw, thanks a lot to areca to provide such detailed hardware informations, it's just the wrong format..) - remove the SCSISTAT_* defines, and use the generic ones from instead. Dito for various other SAM defines. - the driver has just two files and should go directly into drivers/scsi instead of a subdirectory Signed-off-by: Andrew Morton --- Documentation/scsi/ChangeLog.arcmsr | 56 drivers/scsi/Kconfig | 25 drivers/scsi/Makefile | 1 drivers/scsi/arcmsr/Makefile | 4 drivers/scsi/arcmsr/arcmsr.c | 2125 ++++++++++++++++++++++++++ drivers/scsi/arcmsr/arcmsr.h | 1242 +++++++++++++++ 6 files changed, 3453 insertions(+) diff -puN /dev/null Documentation/scsi/ChangeLog.arcmsr --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ devel-akpm/Documentation/scsi/ChangeLog.arcmsr 2006-03-08 00:13:09.000000000 -0800 @@ -0,0 +1,56 @@ +************************************************************************** +** History +** +** REV# DATE NAME DESCRIPTION +** 1.00.00.00 3/31/2004 Erich Chen First release +** 1.10.00.04 7/28/2004 Erich Chen modify for ioctl +** 1.10.00.06 8/28/2004 Erich Chen modify for 2.6.x +** 1.10.00.08 9/28/2004 Erich Chen modify for x86_64 +** 1.10.00.10 10/10/2004 Erich Chen bug fix for SMP & ioctl +** 1.20.00.00 11/29/2004 Erich Chen bug fix with arcmsr_bus_reset when PHY error +** 1.20.00.02 12/09/2004 Erich Chen bug fix with over 2T bytes RAID Volume +** 1.20.00.04 1/09/2005 Erich Chen fits for Debian linux kernel version 2.2.xx +** 1.20.00.05 2/20/2005 Erich Chen cleanly as look like a Linux driver at 2.6.x +** thanks for peoples kindness comment +** Kornel Wieliczek +** Christoph Hellwig +** Adrian Bunk +** Andrew Morton +** Christoph Hellwig +** James Bottomley +** Arjan van de Ven +** 1.20.00.06 3/12/2005 Erich Chen fix with arcmsr_pci_unmap_dma "unsigned long" cast, +** modify PCCB POOL allocated by "dma_alloc_coherent" +** (Kornel Wieliczek's comment) +** 1.20.00.07 3/23/2005 Erich Chen bug fix with arcmsr_scsi_host_template_init +** occur segmentation fault, +** if RAID adapter does not on PCI slot +** and modprobe/rmmod this driver twice. +** bug fix enormous stack usage (Adrian Bunk's comment) +** 1.20.00.08 6/23/2005 Erich Chen bug fix with abort command, +** in case of heavy loading when sata cable +** working on low quality connection +** 1.20.00.09 9/12/2005 Erich Chen bug fix with abort command handling, firmware version check +** and firmware update notify for hardware bug fix +** 1.20.00.10 9/23/2005 Erich Chen enhance sysfs function for change driver's max tag Q number. +** add DMA_64BIT_MASK for backward compatible with all 2.6.x +** add some useful message for abort command +** add ioctl code 'ARCMSR_IOCTL_FLUSH_ADAPTER_CACHE' +** customer can send this command for sync raid volume data +** 1.20.00.11 9/29/2005 Erich Chen by comment of Arjan van de Ven fix incorrect msleep redefine +** cast off sizeof(dma_addr_t) condition for 64bit pci_set_dma_mask +** 1.20.00.12 9/30/2005 Erich Chen bug fix with 64bit platform's ccbs using if over 4G system memory +** change 64bit pci_set_consistent_dma_mask into 32bit +** increcct adapter count if adapter initialize fail. +** miss edit at arcmsr_build_ccb.... +** psge += sizeof(struct _SG64ENTRY *) => +** psge += sizeof(struct _SG64ENTRY) +** 64 bits sg entry would be incorrectly calculated +** thanks Kornel Wieliczek give me kindly notify +** and detail description +** 1.20.00.13 11/15/2005 Erich Chen scheduling pending ccb with FIFO +** change the architecture of arcmsr command queue list +** for linux standard list +** enable usage of pci message signal interrupt +** follow Randy.Danlup kindness suggestion cleanup this code +************************************************************************** \ No newline at end of file diff -puN /dev/null drivers/scsi/arcmsr/arcmsr.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ devel-akpm/drivers/scsi/arcmsr/arcmsr.c 2006-03-08 00:13:09.000000000 -0800 @@ -0,0 +1,2125 @@ +/* +******************************************************************************* +** O.S : Linux +** FILE NAME : arcmsr.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: erich@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 +******************************************************************************* +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "arcmsr.h" + +MODULE_AUTHOR("Erich Chen "); +MODULE_DESCRIPTION("ARECA (ARC11xx/12xx) SATA RAID HOST Adapter"); +MODULE_LICENSE("Dual BSD/GPL"); + +/* +******************************************************************************* +******************************************************************************* +*/ +static uint8_t arcmsr_adapterCnt; +static struct HCBARC arcmsr_host_control_block; +/* +******************************************************************************* +******************************************************************************* +*/ +static int arcmsr_fops_close(struct inode *inode, struct file *filep); +static int arcmsr_fops_open(struct inode *inode, struct file *filep); +static int arcmsr_initialize(struct ACB *pACB, struct pci_dev *pci_device); +static int arcmsr_iop_ioctlcmd(struct ACB *pACB, int ioctl_cmd, void __user * arg); +static int arcmsr_release(struct Scsi_Host *); +static int arcmsr_cmd_abort(struct scsi_cmnd *); +static int arcmsr_bus_reset(struct scsi_cmnd *); +static int arcmsr_ioctl(struct scsi_device * dev, int ioctl_cmd, void __user * arg); +static int arcmsr_fops_ioctl(struct inode *inode, struct file *filep, + unsigned int ioctl_cmd, unsigned long arg); +static int arcmsr_halt_notify(struct notifier_block *nb, + unsigned long event, void *buf); +static int arcmsr_proc_info(struct Scsi_Host *host, char *buffer, char **start, + off_t offset, int length, int inout); +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_device_probe(struct pci_dev *pci_device, + const struct pci_device_id *id); +static void arcmsr_device_remove(struct pci_dev *pci_device); +static void arcmsr_pcidev_disattach(struct ACB *pACB); +static void arcmsr_iop_init(struct ACB *pACB); +static void arcmsr_free_ccb_pool(struct ACB *pACB); +static irqreturn_t arcmsr_interrupt(struct ACB *pACB); +static uint8_t arcmsr_wait_msgint_ready(struct ACB *pACB); +static const char *arcmsr_info(struct Scsi_Host *); +/* +******************************************************************************* +******************************************************************************* +*/ +static ssize_t arcmsr_show_firmware_info(struct class_device *dev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(dev); + struct ACB *pACB = (struct ACB *) host->hostdata; + unsigned long flags = 0; + ssize_t len; + + spin_lock_irqsave(pACB->host->host_lock, flags); + len = snprintf(buf, PAGE_SIZE, + "=================================\n" + "Firmware Version: %s\n" + "Adapter Model: %s\n" + "Reguest Lenth: %4d\n" + "Numbers of Queue: %4d\n" + "SDRAM Size: %4d\n" + "IDE Channels: %4d\n" + "=================================\n", + pACB->firm_version, + pACB->firm_model, + pACB->firm_request_len, + pACB->firm_numbers_queue, + pACB->firm_sdram_size, + pACB->firm_ide_channels); + spin_unlock_irqrestore(pACB->host->host_lock, flags); + return len; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static ssize_t arcmsr_show_driver_state(struct class_device *dev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(dev); + struct ACB *pACB = (struct ACB *)host->hostdata; + unsigned long flags = 0; + ssize_t len; + + spin_lock_irqsave(pACB->host->host_lock, flags); + len = snprintf(buf, PAGE_SIZE, + "=================================\n" + "ARCMSR: %s\n" + "Current commands posted: %4d\n" + "Max commands posted: %4d\n" + "Current pending commands: %4d\n" + "Max pending commands: %4d\n" + "Max sgl length: %4d\n" + "Max sector count: %4d\n" + "SCSI Host Resets: %4d\n" + "SCSI Aborts/Timeouts: %4d\n" + "=================================\n", + ARCMSR_DRIVER_VERSION, + atomic_read(&pACB->ccboutstandingcount), + ARCMSR_MAX_OUTSTANDING_CMD, + atomic_read(&pACB->ccbpendingcount), + ARCMSR_MAX_PENDING_CMD, + ARCMSR_MAX_SG_ENTRIES, + ARCMSR_MAX_XFER_SECTORS, + pACB->num_resets, + pACB->num_aborts); + spin_unlock_irqrestore(pACB->host->host_lock, flags); + return len; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static struct class_device_attribute arcmsr_firmware_info_attr = { + .attr = { + .name = "firmware_info", + .mode = S_IRUGO, + }, + .show = arcmsr_show_firmware_info, +}; +/* +******************************************************************************* +******************************************************************************* +*/ +static struct class_device_attribute arcmsr_driver_state_attr = { + .attr = { + .name = "driver_state", + .mode = S_IRUGO, + }, + .show = arcmsr_show_driver_state +}; +/* +******************************************************************************* +******************************************************************************* +*/ +static struct class_device_attribute *arcmsr_scsi_host_attr[] = { + &arcmsr_firmware_info_attr, + &arcmsr_driver_state_attr, + NULL +}; +/* +******************************************************************************* +******************************************************************************* +*/ +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, + .proc_name = "arcmsr", + .proc_info = arcmsr_proc_info, + .name = "ARCMSR ARECA SATA RAID HOST Adapter" ARCMSR_DRIVER_VERSION, + .release = arcmsr_release, + .info = arcmsr_info, + .ioctl = arcmsr_ioctl, + .queuecommand = arcmsr_queue_command, + .eh_abort_handler = arcmsr_cmd_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, + .unchecked_isa_dma = 0, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = arcmsr_scsi_host_attr, +}; +/* +******************************************************************************* +** notifier block to get a notify on system shutdown/halt/reboot +******************************************************************************* +*/ +static struct notifier_block arcmsr_event_notifier = { + .notifier_call = arcmsr_halt_notify +}; +/* +******************************************************************************* +******************************************************************************* +*/ +static struct file_operations arcmsr_file_operations = { + .owner = THIS_MODULE, + .ioctl = arcmsr_fops_ioctl, + .open = arcmsr_fops_open, + .release = arcmsr_fops_close, +}; +/* +******************************************************************************* +******************************************************************************* +*/ +static struct pci_device_id arcmsr_device_id_table[] = { + {PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1110)}, + {PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1120)}, + {PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1130)}, + {PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1160)}, + {PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1170)}, + {PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1210)}, + {PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1220)}, + {PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1230)}, + {PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1260)}, + {PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1270)}, + {PCI_DEVICE(PCIVendorIDARECA, PCIDeviceIDARC1280)}, + {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_device_probe, + .remove = arcmsr_device_remove, +}; +/* +******************************************************************************* +******************************************************************************* +*/ +static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + irqreturn_t handle_state; + struct HCBARC *pHCBARC = &arcmsr_host_control_block; + struct ACB *pACB; + struct ACB *pACBtmp; + unsigned long flags; + int i = 0; + + pACB = (struct ACB *)dev_id; + pACBtmp = pHCBARC->pACB[i]; + while ((pACB != pACBtmp) && pACBtmp && (i < ARCMSR_MAX_ADAPTER) ) { + i++; + pACBtmp = pHCBARC->pACB[i]; + } + if (!pACBtmp) + return IRQ_NONE; + spin_lock_irqsave(pACB->host->host_lock, flags); + handle_state = arcmsr_interrupt(pACB); + spin_unlock_irqrestore(pACB->host->host_lock, flags); + 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 int arcmsr_device_probe(struct pci_dev *pci_device, + const struct pci_device_id *id) +{ + struct Scsi_Host *host; + struct HCBARC *pHCBARC = &arcmsr_host_control_block; + struct ACB *pACB; + uint8_t bus, dev_fun; + + if (pci_enable_device(pci_device)) { + printk(KERN_NOTICE + "arcmsr%d: adapter probe: pci_enable_device error \n" + , arcmsr_adapterCnt); + return -ENODEV; + } + host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof (struct ACB)); + if (!host) { + printk(KERN_NOTICE + "arcmsr%d: adapter probe: scsi_host_alloc error \n" + , arcmsr_adapterCnt); + return -ENODEV; + } + if (!pci_set_dma_mask(pci_device, DMA_64BIT_MASK)) + printk(KERN_INFO + "ARECA RAID ADAPTER%d: 64BITS PCI BUS DMA ADDRESSING SUPPORTED\n" + , arcmsr_adapterCnt); + else if (!pci_set_dma_mask(pci_device, DMA_32BIT_MASK)) + printk(KERN_INFO + "ARECA RAID ADAPTER%d: 32BITS PCI BUS DMA ADDRESSING SUPPORTED\n" + , arcmsr_adapterCnt); + else { + printk(KERN_NOTICE + "ARECA RAID ADAPTER%d: No suitable DMA available.\n" + , arcmsr_adapterCnt); + return -ENOMEM; + } + if (pci_set_consistent_dma_mask(pci_device, DMA_32BIT_MASK)) { + printk(KERN_NOTICE + "ARECA RAID ADAPTER%d:" + " No 32BIT coherent DMA adressing available\n" + , arcmsr_adapterCnt); + return -ENOMEM; + } + bus = pci_device->bus->number; + dev_fun = pci_device->devfn; + pACB = (struct ACB *) host->hostdata; + memset(pACB, 0, sizeof (struct ACB)); + spin_lock_init(&pACB->qbuffer_lock); + spin_lock_init(&pACB->pending_list_lock); + spin_lock_init(&pACB->working_list_lock); + spin_lock_init(&pACB->done_list_lock); + pACB->pci_device = pci_device; + pACB->host = host; + 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->io_port = 0; + host->n_io_port = 0; + host->irq = pci_device->irq; + pci_set_master(pci_device); + if (arcmsr_initialize(pACB, pci_device)) { + printk(KERN_NOTICE + "arcmsr%d: initialize got error \n" + , arcmsr_adapterCnt); + pHCBARC->adapterCnt = arcmsr_adapterCnt; + pHCBARC->pACB[arcmsr_adapterCnt] = NULL; + scsi_remove_host(host); + scsi_host_put(host); + return -ENODEV; + } + if (pci_request_regions(pci_device, "arcmsr")) { + printk(KERN_NOTICE + "arcmsr%d: adapter probe: pci_request_regions failed \n" + , arcmsr_adapterCnt--); + pHCBARC->adapterCnt = arcmsr_adapterCnt; + arcmsr_pcidev_disattach(pACB); + return -ENODEV; + } +#ifdef CONFIG_SCSI_ARCMSR_MSI + if (!pci_enable_msi(pci_device)) + pACB->acb_flags |= ACB_F_HAVE_MSI; +#endif + if (request_irq(pci_device->irq, arcmsr_do_interrupt, SA_INTERRUPT | SA_SHIRQ, + "arcmsr", pACB)) { + printk(KERN_NOTICE + "arcmsr%d: request IRQ=%d failed !\n" + , arcmsr_adapterCnt--, pci_device->irq); + pHCBARC->adapterCnt = arcmsr_adapterCnt; + arcmsr_pcidev_disattach(pACB); + return -ENODEV; + } + arcmsr_iop_init(pACB); + if (scsi_add_host(host, &pci_device->dev)) { + printk(KERN_NOTICE + "arcmsr%d: scsi_add_host got error \n" + , arcmsr_adapterCnt--); + pHCBARC->adapterCnt = arcmsr_adapterCnt; + arcmsr_pcidev_disattach(pACB); + return -ENODEV; + } + pHCBARC->adapterCnt = arcmsr_adapterCnt; + pci_set_drvdata(pci_device, host); + scsi_scan_host(host); + return 0; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_device_remove(struct pci_dev *pci_device) +{ + struct Scsi_Host * host = pci_get_drvdata(pci_device); + struct ACB *pACB = (struct ACB *) host->hostdata; + struct HCBARC *pHCBARC = &arcmsr_host_control_block; + int i; + + arcmsr_pcidev_disattach(pACB); + /*if this is last pACB */ + for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) { + if (pHCBARC->pACB[i]) + return;/* this is not last adapter's release */ + } + unregister_chrdev(pHCBARC->arcmsr_major_number, "arcmsr"); + unregister_reboot_notifier(&arcmsr_event_notifier); +} +/* +******************************************************************************* +******************************************************************************* +*/ +static int arcmsr_scsi_host_template_init( + struct scsi_host_template * host_template) +{ + int error; + struct HCBARC *pHCBARC = &arcmsr_host_control_block; + + /* + ** register as a PCI hot-plug driver module+ + */ + memset(pHCBARC, 0, sizeof (struct HCBARC)); + error = pci_module_init(&arcmsr_pci_driver); + if (pHCBARC->pACB[0]) { + host_template->proc_name = "arcmsr"; + register_reboot_notifier(&arcmsr_event_notifier); + pHCBARC->arcmsr_major_number = register_chrdev(0, "arcmsr" + , &arcmsr_file_operations); + printk(KERN_INFO + "arcmsr device major number %d \n" + , pHCBARC->arcmsr_major_number); + } + return error; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static int arcmsr_module_init(void) +{ + return(arcmsr_scsi_host_template_init(&arcmsr_scsi_host_template)); +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_module_exit(void) +{ + pci_unregister_driver(&arcmsr_pci_driver); +} +module_init(arcmsr_module_init); +module_exit(arcmsr_module_exit); +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_pci_unmap_dma(struct CCB *pCCB) +{ + struct ACB *pACB = pCCB->pACB; + struct scsi_cmnd *pcmd = pCCB->pcmd; + + if (pcmd->use_sg != 0) { + struct scatterlist *sl; + + sl = (struct scatterlist *)pcmd->request_buffer; + pci_unmap_sg(pACB->pci_device, sl, pcmd->use_sg, pcmd->sc_data_direction); + } + else if (pcmd->request_bufflen != 0) + pci_unmap_single(pACB->pci_device, + (dma_addr_t)(unsigned long)pcmd->SCp.ptr, + pcmd->request_bufflen, pcmd->sc_data_direction); +} +/* +******************************************************************************* +******************************************************************************* +*/ +static int arcmsr_fops_open(struct inode *inode, struct file *filep) +{ + int i, minor; + struct HCBARC *pHCBARC = &arcmsr_host_control_block; + struct ACB *pACB; + + minor = MINOR(inode->i_rdev); + if (minor >= pHCBARC->adapterCnt) + return -ENODEV; + for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) { + pACB = pHCBARC->pACB[i]; + if (pACB) { + if (pACB->adapter_index == minor) + break; + } + } + if (i >= ARCMSR_MAX_ADAPTER) + return -ENODEV; + return 0;/* success */ +} +/* +******************************************************************************* +******************************************************************************* +*/ +static int arcmsr_fops_close(struct inode *inode, struct file *filep) +{ + int i, minor; + struct HCBARC *pHCBARC = &arcmsr_host_control_block; + struct ACB *pACB; + + minor = MINOR(inode->i_rdev); + if (minor >= pHCBARC->adapterCnt) + return -ENODEV; + for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) { + pACB = pHCBARC->pACB[i]; + if (pACB) { + if (pACB->adapter_index == minor) + break; + } + } + if (i >= ARCMSR_MAX_ADAPTER) + return -ENODEV; + return 0; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static int arcmsr_fops_ioctl(struct inode *inode, struct file *filep, + unsigned int ioctl_cmd, unsigned long arg) +{ + int i, minor; + struct HCBARC *pHCBARC = &arcmsr_host_control_block; + struct ACB *pACB; + + minor = MINOR(inode->i_rdev); + if (minor >= pHCBARC->adapterCnt) + return -ENODEV; + for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) { + pACB = pHCBARC->pACB[i]; + if (pACB) { + if (pACB->adapter_index == minor) + break; + } + } + if (i >= ARCMSR_MAX_ADAPTER) + return -ENODEV; + return arcmsr_iop_ioctlcmd(pACB, ioctl_cmd, (void __user *) arg); +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_flush_adapter_cache(struct ACB *pACB) +{ + struct MU __iomem *reg=pACB->pmu; + + writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); + if (arcmsr_wait_msgint_ready(pACB)) + printk(KERN_NOTICE + "arcmsr%d: wait 'flush adapter cache' timeout \n" + , pACB->adapter_index); +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_ccb_complete(struct CCB *pCCB, int stand_flag) +{ + unsigned long flags; + struct ACB *pACB = pCCB->pACB; + struct scsi_cmnd *pcmd = pCCB->pcmd; + + arcmsr_pci_unmap_dma(pCCB); + spin_lock_irqsave(&pACB->done_list_lock, flags); + if (stand_flag == 1) + atomic_dec(&pACB->ccboutstandingcount); + pCCB->startdone = ARCMSR_CCB_DONE; + pCCB->ccb_flags = 0; + list_add_tail(&pCCB->list, &pACB->ccb_free_list); + spin_unlock_irqrestore(&pACB->done_list_lock, flags); + pcmd->scsi_done(pcmd); +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_report_sense_info(struct CCB *pCCB) +{ + struct scsi_cmnd *pcmd = pCCB->pcmd; + struct SENSE_DATA *psenseBuffer = (struct SENSE_DATA *)pcmd->sense_buffer; + + pcmd->result = DID_OK << 16; + if (psenseBuffer) { + int sense_data_length = + sizeof (struct SENSE_DATA) < sizeof (pcmd->sense_buffer) + ? sizeof (struct SENSE_DATA) : sizeof (pcmd->sense_buffer); + memset(psenseBuffer, 0, sizeof (pcmd->sense_buffer)); + memcpy(psenseBuffer, pCCB->arcmsr_cdb.SenseData, sense_data_length); + psenseBuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS; + psenseBuffer->Valid = 1; + } +} +/* +******************************************************************************* +** to insert pCCB into tail of pACB wait exec ccbQ +******************************************************************************* +*/ +static void arcmsr_queue_pendingccb(struct ACB *pACB, struct CCB *pCCB) +{ + unsigned long flags; + + spin_lock_irqsave(&pACB->pending_list_lock, flags); + list_add_tail(&pCCB->list, &pACB->ccb_pending_list); + atomic_inc(&pACB->ccbpendingcount); + spin_unlock_irqrestore(&pACB->pending_list_lock, flags); +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_abort_allcmd(struct ACB *pACB) +{ + struct MU __iomem *reg = pACB->pmu; + + writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0); + if (arcmsr_wait_msgint_ready(pACB)) + printk(KERN_NOTICE + "arcmsr%d: wait 'abort all outstanding command' timeout \n" + , pACB->adapter_index); +} +/* +******************************************************************************* +******************************************************************************* +*/ +static uint8_t arcmsr_wait_msgint_ready(struct ACB *pACB) +{ + struct MU __iomem *reg = pACB->pmu; + uint32_t Index; + uint8_t Retries = 0x00; + + do { + for(Index = 0; Index < 100; Index++) { + if (readl(®->outbound_intstatus) + & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { + writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT + , ®->outbound_intstatus); + return 0x00; + } + msleep_interruptible(10); + }/*max 1 seconds*/ + } while (Retries++ < 20);/*max 20 sec*/ + return 0xff; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static struct CCB *arcmsr_get_pendingccb(struct ACB *pACB) +{ + unsigned long flags; + struct list_head *head = &pACB->ccb_pending_list; + struct CCB *pCCB = NULL; + + if (spin_trylock_irqsave(&pACB->pending_list_lock, flags)) { + if (!list_empty(head)) { + pCCB = list_entry(head->next, struct CCB, list); + atomic_dec(&pACB->ccbpendingcount); + list_del(head->next); + } + spin_unlock_irqrestore(&pACB->pending_list_lock, flags); + } + return pCCB; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_iop_reset(struct ACB *pACB) +{ + struct MU __iomem *reg = pACB->pmu; + struct CCB *pCCB; + uint32_t intmask_org, mask; + int i = 0; + + if (atomic_read(&pACB->ccboutstandingcount) != 0) { + /* talk to iop 331 outstanding command aborted */ + arcmsr_abort_allcmd(pACB); + /* wait for 3 sec for all command aborted*/ + msleep_interruptible(3000); + /* disable all outbound interrupt */ + intmask_org = readl(®->outbound_intmask); + writel(intmask_org | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, + ®->outbound_intmask); + /* clear all outbound posted Q */ + for(i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++) + readl(®->outbound_queueport); + for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { + pCCB = pACB->pccb_pool[i]; + if (pCCB->startdone == ARCMSR_CCB_START) { + pCCB->startdone = ARCMSR_CCB_ABORTED; + pCCB->pcmd->result = DID_ABORT << 16; + arcmsr_ccb_complete(pCCB, 1); + } + } + /* enable all outbound interrupt */ + mask =~ (ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE + | ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); + writel(intmask_org & mask, ®->outbound_intmask); + } + while (atomic_read(&pACB->ccbpendingcount) != 0) { + pCCB = arcmsr_get_pendingccb(pACB); + if (pCCB) { + printk(KERN_NOTICE + "arcmsr%d:iop reset abort command ccbpendingcount=%d \n" + , pACB->adapter_index, atomic_read(&pACB->ccbpendingcount)); + pCCB->startdone = ARCMSR_CCB_ABORTED; + pCCB->pcmd->result = DID_ABORT << 16; + arcmsr_ccb_complete(pCCB, 0); + atomic_dec(&pACB->ccbpendingcount); + } + else + break; + } + atomic_set(&pACB->ccboutstandingcount, 0); + atomic_set(&pACB->ccbpendingcount, 0); +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_build_ccb(struct ACB *pACB, struct CCB *pCCB, + struct scsi_cmnd *pcmd) +{ + struct ARCMSR_CDB *pARCMSR_CDB = (struct ARCMSR_CDB *)&pCCB->arcmsr_cdb; + int8_t *psge = (int8_t *)&pARCMSR_CDB->u; + uint32_t address_lo, address_hi; + int arccdbsize = 0x30; + + pCCB->pcmd = pcmd; + memset(pARCMSR_CDB, 0, sizeof (struct ARCMSR_CDB)); + pARCMSR_CDB->Bus = 0; + pARCMSR_CDB->TargetID = pcmd->device->id; + pARCMSR_CDB->LUN = pcmd->device->lun; + pARCMSR_CDB->Function = 1; + pARCMSR_CDB->CdbLength = (uint8_t)pcmd->cmd_len; + pARCMSR_CDB->Context = (unsigned long)pARCMSR_CDB; + memcpy(pARCMSR_CDB->Cdb, pcmd->cmnd, pcmd->cmd_len); + if (pcmd->use_sg) { + int length, sgcount, i, cdb_sgcount = 0; + struct scatterlist *sl; + + /* Get Scatter Gather List from scsiport. */ + sl = (struct scatterlist *) pcmd->request_buffer; + sgcount = pci_map_sg(pACB->pci_device, sl, pcmd->use_sg, + pcmd->sc_data_direction); + /* map stor port SG list to our iop SG List. */ + for(i = 0; i < sgcount; i++) { + /* Get the physical address of the current data pointer */ + length = cpu_to_le32(sg_dma_len(sl)); + address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sl))); + address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sl))); + if (address_hi == 0) { + struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge; + + pdma_sg->address = address_lo; + pdma_sg->length = length; + psge += sizeof (struct SG32ENTRY); + arccdbsize += sizeof (struct SG32ENTRY); + } else { + struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge; + + pdma_sg->addresshigh = address_hi; + pdma_sg->address = address_lo; + pdma_sg->length = length|IS_SG64_ADDR; + psge += sizeof (struct SG64ENTRY); + arccdbsize += sizeof (struct SG64ENTRY); + } + sl++; + cdb_sgcount++; + } + pARCMSR_CDB->sgcount = (uint8_t)cdb_sgcount; + pARCMSR_CDB->DataLength = pcmd->request_bufflen; + if ( arccdbsize > 256) + pARCMSR_CDB->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE; + } else if (pcmd->request_bufflen) { + dma_addr_t dma_addr; + dma_addr = pci_map_single(pACB->pci_device, pcmd->request_buffer, + pcmd->request_bufflen, pcmd->sc_data_direction); + pcmd->SCp.ptr = (char *)(unsigned long) dma_addr; + address_lo = cpu_to_le32(dma_addr_lo32(dma_addr)); + address_hi = cpu_to_le32(dma_addr_hi32(dma_addr)); + if (address_hi == 0) { + struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge; + pdma_sg->address = address_lo; + pdma_sg->length = pcmd->request_bufflen; + } else { + struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge; + pdma_sg->addresshigh = address_hi; + pdma_sg->address = address_lo; + pdma_sg->length = pcmd->request_bufflen|IS_SG64_ADDR; + } + pARCMSR_CDB->sgcount = 1; + pARCMSR_CDB->DataLength = pcmd->request_bufflen; + } + if (pcmd->cmnd[0] | WRITE_6 || pcmd->cmnd[0] | WRITE_10) { + pARCMSR_CDB->Flags |= ARCMSR_CDB_FLAG_WRITE; + pCCB->ccb_flags |= CCB_FLAG_WRITE; + } +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_post_ccb(struct ACB *pACB, struct CCB *pCCB) +{ + struct MU __iomem *reg = pACB->pmu; + uint32_t cdb_shifted_phyaddr = pCCB->cdb_shifted_phyaddr; + struct ARCMSR_CDB *pARCMSR_CDB = (struct ARCMSR_CDB *)&pCCB->arcmsr_cdb; + + atomic_inc(&pACB->ccboutstandingcount); + pCCB->startdone = ARCMSR_CCB_START; + if (pARCMSR_CDB->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) + writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE, + ®->inbound_queueport); + else + writel(cdb_shifted_phyaddr, ®->inbound_queueport); +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_post_pendingccb(struct ACB *pACB) +{ + struct CCB *pCCB; + + while ((atomic_read(&pACB->ccbpendingcount) > 0) + && (atomic_read(&pACB->ccboutstandingcount) < ARCMSR_MAX_OUTSTANDING_CMD)) { + pCCB = arcmsr_get_pendingccb(pACB); + if (!pCCB) + break; + arcmsr_post_ccb(pACB, pCCB); + } +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_post_Qbuffer(struct ACB *pACB) +{ + struct MU __iomem *reg = pACB->pmu; + struct QBUFFER __iomem *pwbuffer = (struct QBUFFER __iomem *) ®->ioctl_wbuffer; + uint8_t __iomem *iop_data = (uint8_t __iomem *) pwbuffer->data; + int32_t allxfer_len = 0; + + if (pACB->acb_flags & ACB_F_IOCTL_WQBUFFER_READED) { + pACB->acb_flags &= (~ACB_F_IOCTL_WQBUFFER_READED); + while ((pACB->wqbuf_firstindex != pACB->wqbuf_lastindex) + && (allxfer_len < 124)) { + writeb(pACB->wqbuffer[pACB->wqbuf_firstindex], iop_data); + pACB->wqbuf_firstindex++; + pACB->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; + iop_data++; + allxfer_len++; + } + writel(allxfer_len, &pwbuffer->data_len); + writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK + , ®->inbound_doorbell); + } +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_stop_adapter_bgrb(struct ACB *pACB) +{ + struct MU __iomem *reg = pACB->pmu; + + pACB->acb_flags &= ~ACB_F_MSG_START_BGRB; + writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0); + if (arcmsr_wait_msgint_ready(pACB)) + printk(KERN_NOTICE + "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" + , pACB->adapter_index); +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_free_ccb_pool(struct ACB *pACB) +{ + dma_free_coherent(&pACB->pci_device->dev + , ARCMSR_MAX_FREECCB_NUM * sizeof (struct CCB) + 0x20, + pACB->dma_coherent, + pACB->dma_coherent_handle); +} +/* +******************************************************************************* +******************************************************************************* +*/ +static irqreturn_t arcmsr_interrupt(struct ACB *pACB) +{ + struct MU __iomem *reg = pACB->pmu; + struct CCB *pCCB; + uint32_t flag_ccb, outbound_intstatus, outbound_doorbell; + + outbound_intstatus = readl(®->outbound_intstatus) + & pACB->outbound_int_enable; + writel(outbound_intstatus, ®->outbound_intstatus); + if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) { + outbound_doorbell = readl(®->outbound_doorbell); + writel(outbound_doorbell, ®->outbound_doorbell); + if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { + struct QBUFFER __iomem * prbuffer = + (struct QBUFFER __iomem *) ®->ioctl_rbuffer; + uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data; + int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex; + + rqbuf_lastindex = pACB->rqbuf_lastindex; + rqbuf_firstindex = pACB->rqbuf_firstindex; + iop_len = readl(&prbuffer->data_len); + my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) + &(ARCMSR_MAX_QBUFFER - 1); + if (my_empty_len >= iop_len) { + while (iop_len > 0) { + pACB->rqbuffer[pACB->rqbuf_lastindex] = readb(iop_data); + pACB->rqbuf_lastindex++; + pACB->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; + iop_data++; + iop_len--; + } + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, + ®->inbound_doorbell); + } else + pACB->acb_flags |= ACB_F_IOPDATA_OVERFLOW; + } + if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) { + pACB->acb_flags |= ACB_F_IOCTL_WQBUFFER_READED; + if (pACB->wqbuf_firstindex != pACB->wqbuf_lastindex) { + struct QBUFFER __iomem * pwbuffer = + (struct QBUFFER __iomem *) ®->ioctl_wbuffer; + uint8_t __iomem * iop_data = (uint8_t __iomem *) pwbuffer->data; + int32_t allxfer_len = 0; + + pACB->acb_flags &= (~ACB_F_IOCTL_WQBUFFER_READED); + while ((pACB->wqbuf_firstindex != pACB->wqbuf_lastindex) + && (allxfer_len < 124)) { + writeb(pACB->wqbuffer[pACB->wqbuf_firstindex], iop_data); + pACB->wqbuf_firstindex++; + pACB->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; + iop_data++; + allxfer_len++; + } + writel(allxfer_len, &pwbuffer->data_len); + writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, + ®->inbound_doorbell); + } + if (pACB->wqbuf_firstindex == pACB->wqbuf_lastindex) + pACB->acb_flags |= ACB_F_IOCTL_WQBUFFER_CLEARED; + } + } + if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) { + int id, lun; + /* + **************************************************************** + ** areca cdb command done + **************************************************************** + */ + while (1) { + if ((flag_ccb = readl(®->outbound_queueport)) == 0xFFFFFFFF) + break;/*chip FIFO no ccb for completion already*/ + /* check if command done with no error*/ + pCCB = (struct CCB *)(pACB->vir2phy_offset + (flag_ccb << 5)); + if ((pCCB->pACB != pACB) || (pCCB->startdone != ARCMSR_CCB_START)) { + if (pCCB->startdone == ARCMSR_CCB_ABORTED) { + printk(KERN_NOTICE + "arcmsr%d: ccb='0x%p' isr got aborted command \n" + , pACB->adapter_index, pCCB); + continue; + } + printk(KERN_NOTICE + "arcmsr%d: isr get an illegal ccb command done acb='0x%p'" + "ccb='0x%p' ccbacb='0x%p' startdone = 0x%x" + " ccboutstandingcount=%d \n" + , pACB->adapter_index + , pACB + , pCCB + , pCCB->pACB + , pCCB->startdone + , atomic_read(&pACB->ccboutstandingcount)); + continue; + } + id = pCCB->pcmd->device->id; + lun = pCCB->pcmd->device->lun; + if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { + if (pACB->devstate[id][lun] == ARECA_RAID_GONE) + pACB->devstate[id][lun] = ARECA_RAID_GOOD; + pCCB->pcmd->result = DID_OK << 16; + arcmsr_ccb_complete(pCCB, 1); + } else { + switch(pCCB->arcmsr_cdb.DeviceStatus) { + case ARCMSR_DEV_SELECT_TIMEOUT: { + pACB->devstate[id][lun] = ARECA_RAID_GONE; + pCCB->pcmd->result = DID_TIME_OUT << 16; + arcmsr_ccb_complete(pCCB, 1); + } + break; + case ARCMSR_DEV_ABORTED: + case ARCMSR_DEV_INIT_FAIL: { + pACB->devstate[id][lun] = ARECA_RAID_GONE; + pCCB->pcmd->result = DID_BAD_TARGET << 16; + arcmsr_ccb_complete(pCCB, 1); + } + break; + case SCSISTAT_CHECK_CONDITION: { + pACB->devstate[id][lun] = ARECA_RAID_GOOD; + arcmsr_report_sense_info(pCCB); + arcmsr_ccb_complete(pCCB, 1); + } + break; + default: + printk(KERN_NOTICE + "arcmsr%d: scsi id=%d lun=%d" + " isr get command error done," + "but got unknown DeviceStatus = 0x%x \n" + , pACB->adapter_index + , id + , lun + , pCCB->arcmsr_cdb.DeviceStatus); + pACB->devstate[id][lun] = ARECA_RAID_GONE; + pCCB->pcmd->result = DID_NO_CONNECT << 16; + arcmsr_ccb_complete(pCCB, 1); + break; + } + } + }/*drain reply FIFO*/ + } + if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) + return IRQ_NONE; + arcmsr_post_pendingccb(pACB);/*try to post all pending ccb*/ + return IRQ_HANDLED; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_iop_parking(struct ACB *pACB) +{ + if (pACB) { + /* stop adapter background rebuild */ + if (pACB->acb_flags & ACB_F_MSG_START_BGRB) { + pACB->acb_flags &= ~ACB_F_MSG_START_BGRB; + arcmsr_stop_adapter_bgrb(pACB); + arcmsr_flush_adapter_cache(pACB); + } + } +} +/* +******************************************************************************* +******************************************************************************* +*/ +static int arcmsr_iop_ioctlcmd(struct ACB *pACB, int ioctl_cmd, void __user * arg) +{ + struct MU __iomem *reg = pACB->pmu; + struct CMD_IOCTL_FIELD *pcmdioctlfld; + dma_addr_t cmd_handle; + unsigned long flags; + int retvalue = 0; + + spin_lock_irqsave(&pACB->qbuffer_lock, flags); + pcmdioctlfld = pci_alloc_consistent(pACB->pci_device, + sizeof (struct CMD_IOCTL_FIELD), &cmd_handle); + if (!pcmdioctlfld) { + spin_unlock_irqrestore(&pACB->qbuffer_lock, flags); + return -ENOMEM; + } + if (copy_from_user(pcmdioctlfld, arg, sizeof (struct CMD_IOCTL_FIELD)) != 0) { + retvalue = -EFAULT; + goto ioctl_out; + } + if (memcmp(pcmdioctlfld->cmdioctl.Signature, "ARCMSR", 6) !=0 ) { + retvalue = -EINVAL; + goto ioctl_out; + } + switch(ioctl_cmd) { + case ARCMSR_IOCTL_READ_RQBUFFER: { + unsigned long *ver_addr; + dma_addr_t buf_handle; + uint8_t *pQbuffer,*ptmpQbuffer; + int32_t allxfer_len = 0; + + ver_addr = pci_alloc_consistent(pACB->pci_device, 1032, &buf_handle); + if (!ver_addr) { + retvalue = -ENOMEM; + goto ioctl_out; + } + ptmpQbuffer = (uint8_t *)ver_addr; + while ((pACB->rqbuf_firstindex != pACB->rqbuf_lastindex) + && (allxfer_len < 1031)) { + pQbuffer = &pACB->rqbuffer[pACB->rqbuf_firstindex]; + memcpy(ptmpQbuffer, pQbuffer, 1); + pACB->rqbuf_firstindex++; + pACB->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; + ptmpQbuffer++; + allxfer_len++; + } + if (pACB->acb_flags & ACB_F_IOPDATA_OVERFLOW) { + struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *) + ®->ioctl_rbuffer; + uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data; + int32_t iop_len; + + pACB->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + iop_len = readl(&prbuffer->data_len); + while (iop_len > 0) { + pACB->rqbuffer[pACB->rqbuf_lastindex] = readb(iop_data); + pACB->rqbuf_lastindex++; + pACB->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; + iop_data++; + iop_len--; + } + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, + ®->inbound_doorbell); + } + memcpy(pcmdioctlfld->ioctldatabuffer, (uint8_t *)ver_addr, allxfer_len); + pcmdioctlfld->cmdioctl.Length = allxfer_len; + pcmdioctlfld->cmdioctl.ReturnCode = ARCMSR_IOCTL_RETURNCODE_OK; + if (copy_to_user(arg, pcmdioctlfld, sizeof (struct CMD_IOCTL_FIELD)) != 0) + retvalue = -EFAULT; + pci_free_consistent(pACB->pci_device, 1032, ver_addr, buf_handle); + } + break; + case ARCMSR_IOCTL_WRITE_WQBUFFER: { + unsigned long *ver_addr; + dma_addr_t buf_handle; + int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; + uint8_t *pQbuffer, *ptmpuserbuffer; + + ver_addr = pci_alloc_consistent(pACB->pci_device, 1032, &buf_handle); + if (!ver_addr) { + retvalue = -ENOMEM; + goto ioctl_out; + } + ptmpuserbuffer = (uint8_t *)ver_addr; + user_len = pcmdioctlfld->cmdioctl.Length; + memcpy(ptmpuserbuffer, pcmdioctlfld->ioctldatabuffer, user_len); + wqbuf_lastindex = pACB->wqbuf_lastindex; + wqbuf_firstindex = pACB->wqbuf_firstindex; + if (wqbuf_lastindex != wqbuf_firstindex) { + arcmsr_post_Qbuffer(pACB); + pcmdioctlfld->cmdioctl.ReturnCode = + ARCMSR_IOCTL_RETURNCODE_ERROR; + } else { + my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) + &(ARCMSR_MAX_QBUFFER - 1); + if (my_empty_len >= user_len) { + while (user_len > 0) { + pQbuffer = + &pACB->wqbuffer[pACB->wqbuf_lastindex]; + memcpy(pQbuffer, ptmpuserbuffer, 1); + pACB->wqbuf_lastindex++; + pACB->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; + ptmpuserbuffer++; + user_len--; + } + if (pACB->acb_flags & ACB_F_IOCTL_WQBUFFER_CLEARED) { + pACB->acb_flags &= + ~ACB_F_IOCTL_WQBUFFER_CLEARED; + arcmsr_post_Qbuffer(pACB); + } + pcmdioctlfld->cmdioctl.ReturnCode = + ARCMSR_IOCTL_RETURNCODE_OK; + } + else + pcmdioctlfld->cmdioctl.ReturnCode = + ARCMSR_IOCTL_RETURNCODE_ERROR; + } + if (copy_to_user(arg, pcmdioctlfld, + sizeof (struct CMD_IOCTL_FIELD)) != 0) + retvalue = -EFAULT; + pci_free_consistent(pACB->pci_device, 1032, ver_addr, buf_handle); + } + break; + case ARCMSR_IOCTL_CLEAR_RQBUFFER: { + uint8_t *pQbuffer = pACB->rqbuffer; + + if (pACB->acb_flags & ACB_F_IOPDATA_OVERFLOW) { + pACB->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, + ®->inbound_doorbell); + } + pACB->acb_flags |= ACB_F_IOCTL_RQBUFFER_CLEARED; + pACB->rqbuf_firstindex = 0; + pACB->rqbuf_lastindex = 0; + memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); + pcmdioctlfld->cmdioctl.ReturnCode = ARCMSR_IOCTL_RETURNCODE_OK; + if (copy_to_user(arg, pcmdioctlfld, + sizeof (struct CMD_IOCTL_FIELD)) != 0) + retvalue = -EFAULT; + } + break; + case ARCMSR_IOCTL_CLEAR_WQBUFFER: { + uint8_t *pQbuffer = pACB->wqbuffer; + + if (pACB->acb_flags & ACB_F_IOPDATA_OVERFLOW) { + pACB->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK + , ®->inbound_doorbell); + } + pACB->acb_flags |= + (ACB_F_IOCTL_WQBUFFER_CLEARED | ACB_F_IOCTL_WQBUFFER_READED); + pACB->wqbuf_firstindex = 0; + pACB->wqbuf_lastindex = 0; + memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); + pcmdioctlfld->cmdioctl.ReturnCode = ARCMSR_IOCTL_RETURNCODE_OK; + if (copy_to_user(arg, pcmdioctlfld, + sizeof (struct CMD_IOCTL_FIELD)) != 0) + retvalue = -EFAULT; + } + break; + case ARCMSR_IOCTL_CLEAR_ALLQBUFFER: { + uint8_t *pQbuffer; + + if (pACB->acb_flags & ACB_F_IOPDATA_OVERFLOW) { + pACB->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK + , ®->inbound_doorbell); + } + pACB->acb_flags |= + (ACB_F_IOCTL_WQBUFFER_CLEARED + | ACB_F_IOCTL_RQBUFFER_CLEARED + | ACB_F_IOCTL_WQBUFFER_READED); + pACB->rqbuf_firstindex = 0; + pACB->rqbuf_lastindex = 0; + pACB->wqbuf_firstindex = 0; + pACB->wqbuf_lastindex = 0; + pQbuffer = pACB->rqbuffer; + memset(pQbuffer, 0, sizeof (struct QBUFFER)); + pQbuffer = pACB->wqbuffer; + memset(pQbuffer, 0, sizeof (struct QBUFFER)); + pcmdioctlfld->cmdioctl.ReturnCode = ARCMSR_IOCTL_RETURNCODE_OK; + if (copy_to_user(arg, pcmdioctlfld, + sizeof (struct CMD_IOCTL_FIELD)) != 0) + retvalue = -EFAULT; + } + break; + case ARCMSR_IOCTL_RETURN_CODE_3F: { + pcmdioctlfld->cmdioctl.ReturnCode = ARCMSR_IOCTL_RETURNCODE_3F; + if (copy_to_user(arg, pcmdioctlfld, + sizeof (struct CMD_IOCTL_FIELD)) != 0) + retvalue = -EFAULT; + } + break; + case ARCMSR_IOCTL_SAY_HELLO: { + int8_t * hello_string = "Hello! I am ARCMSR"; + + memcpy(pcmdioctlfld->ioctldatabuffer, hello_string + , (int16_t)strlen(hello_string)); + pcmdioctlfld->cmdioctl.ReturnCode = ARCMSR_IOCTL_RETURNCODE_OK; + if (copy_to_user(arg, pcmdioctlfld, + sizeof (struct CMD_IOCTL_FIELD)) != 0) + retvalue = -EFAULT; + } + break; + case ARCMSR_IOCTL_SAY_GOODBYE: + arcmsr_iop_parking(pACB); + break; + case ARCMSR_IOCTL_FLUSH_ADAPTER_CACHE: + arcmsr_flush_adapter_cache(pACB); + break; + default: + retvalue = -EFAULT; + } +ioctl_out: + pci_free_consistent(pACB->pci_device, sizeof (struct CMD_IOCTL_FIELD), + pcmdioctlfld, cmd_handle); + spin_unlock_irqrestore(&pACB->qbuffer_lock, flags); + return retvalue; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static int arcmsr_ioctl(struct scsi_device *dev, int ioctl_cmd, void __user * arg) +{ + struct ACB *pACB; + struct HCBARC *pHCBARC = &arcmsr_host_control_block; + int32_t match = 0x55AA, i; + + for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) { + pACB = pHCBARC->pACB[i]; + if (pACB) { + if (pACB->host == dev->host) { + match = i; + break; + } + } + } + if (match == 0x55AA) + return -ENXIO; + if (!arg) + return -EINVAL; + return(arcmsr_iop_ioctlcmd(pACB, ioctl_cmd, arg)); +} +/* +******************************************************************************* +******************************************************************************* +*/ +static struct CCB *arcmsr_get_freeccb(struct ACB *pACB) +{ + unsigned long flags; + struct list_head *head = &pACB->ccb_free_list; + struct CCB *pCCB = NULL; + + spin_lock_irqsave(&pACB->working_list_lock, flags); + if (!list_empty(head)) { + pCCB = list_entry(head->next, struct CCB, list); + list_del(head->next); + } + spin_unlock_irqrestore(&pACB->working_list_lock, flags); + return pCCB; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static int arcmsr_queue_command(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) +{ + struct Scsi_Host *host = cmd->device->host; + struct ACB *pACB = (struct ACB *) host->hostdata; + struct CCB *pCCB; + int target = cmd->device->id; + int lun = cmd->device->lun; + + cmd->scsi_done = done; + cmd->host_scribble = NULL; + cmd->result = 0; + if (cmd->cmnd[0] == SYNCHRONIZE_CACHE) { + /* + ** 0x35 avoid synchronizing disk cache cmd after + ** .remove : arcmsr_device_remove (linux bug) + */ + if (pACB->devstate[target][lun] == ARECA_RAID_GONE) + cmd->result = (DID_NO_CONNECT << 16); + cmd->scsi_done(cmd); + return 0; + } + if (pACB->acb_flags & ACB_F_BUS_RESET) { + printk(KERN_NOTICE "arcmsr%d: bus reset" + " and return busy \n" + , pACB->adapter_index); + cmd->result = (DID_BUS_BUSY << 16); + cmd->scsi_done(cmd); + return 0; + } + if (pACB->devstate[target][lun] == ARECA_RAID_GONE) { + uint8_t block_cmd; + + block_cmd = cmd->cmnd[0] & 0x0f; + if (block_cmd == 0x08 || block_cmd == 0x0a) { + printk(KERN_NOTICE + "arcmsr%d: block 'read/write'" + "command with gone raid volume" + " Cmd=%2x, TargetId=%d, Lun=%d \n" + , pACB->adapter_index + , cmd->cmnd[0] + , target + , lun); + cmd->result = (DID_NO_CONNECT << 16); + cmd->scsi_done(cmd); + return 0; + } + } + arcmsr_post_pendingccb(pACB); + pCCB = arcmsr_get_freeccb(pACB); + if (pCCB) { + arcmsr_build_ccb(pACB, pCCB, cmd); + if (atomic_read(&pACB->ccboutstandingcount) < ARCMSR_MAX_OUTSTANDING_CMD) { + arcmsr_post_ccb(pACB, pCCB); + return 0; + } + arcmsr_queue_pendingccb(pACB, pCCB); + return 0; + } + printk(KERN_NOTICE + "arcmsr%d: 'out of ccbs resource' ccb outstanding=%d pending=%d \n" + , pACB->adapter_index + , atomic_read(&pACB->ccboutstandingcount) + , atomic_read(&pACB->ccbpendingcount)); + cmd->result = (DID_BUS_BUSY << 16); + cmd->scsi_done(cmd); + return 0; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_get_firmware_spec(struct ACB *pACB) +{ + struct MU __iomem *reg = pACB->pmu; + char *acb_firm_model = pACB->firm_model; + char *acb_firm_version = pACB->firm_version; + char __iomem *iop_firm_model = (char __iomem *) ®->message_rwbuffer[15]; + char __iomem *iop_firm_version = (char __iomem *) ®->message_rwbuffer[17]; + int count; + + writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); + if (arcmsr_wait_msgint_ready(pACB)) + printk(KERN_NOTICE + "arcmsr%d: wait " + "'get adapter firmware miscellaneous data' timeout \n" + , pACB->adapter_index); + count = 8; + while (count) { + *acb_firm_model = readb(iop_firm_model); + acb_firm_model++; + iop_firm_model++; + count--; + } + count = 16; + while (count) { + *acb_firm_version = readb(iop_firm_version); + acb_firm_version++; + iop_firm_version++; + count--; + } + printk(KERN_INFO + "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n" + , pACB->adapter_index + , pACB->firm_version); + pACB->firm_request_len = readl(®->message_rwbuffer[1]); + pACB->firm_numbers_queue = readl(®->message_rwbuffer[2]); + pACB->firm_sdram_size = readl(®->message_rwbuffer[3]); + pACB->firm_ide_channels = readl(®->message_rwbuffer[4]); +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_start_adapter_bgrb(struct ACB *pACB) +{ + struct MU __iomem *reg = pACB->pmu; + pACB->acb_flags |= ACB_F_MSG_START_BGRB; + writel(ARCMSR_INBOUND_MESG0_START_BGRB, ®->inbound_msgaddr0); + if (arcmsr_wait_msgint_ready(pACB)) + printk(KERN_NOTICE + "arcmsr%d: wait 'start adapter background rebulid' timeout \n" + , pACB->adapter_index); +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_polling_ccbdone(struct ACB *pACB, struct CCB *poll_ccb) +{ + struct MU __iomem *reg = pACB->pmu; + struct CCB *pCCB; + uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0; + int id, lun; + +polling_ccb_retry: + poll_count++; + outbound_intstatus = readl(®->outbound_intstatus) + & pACB->outbound_int_enable; + writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ + while (1) { + if ((flag_ccb = readl(®->outbound_queueport)) == 0xFFFFFFFF) { + if (poll_ccb_done) + break; + else { + msleep(25); + if (poll_count > 100) + break; + goto polling_ccb_retry; + } + } + pCCB = (struct CCB *)(pACB->vir2phy_offset + (flag_ccb << 5)); + if ((pCCB->pACB != pACB) || (pCCB->startdone != ARCMSR_CCB_START)) { + if ((pCCB->startdone == ARCMSR_CCB_ABORTED) && (pCCB == poll_ccb)) { + printk(KERN_NOTICE + "arcmsr%d: scsi id=%d lun=%d ccb='0x%p'" + " poll command abort successfully \n" + , pACB->adapter_index + , pCCB->pcmd->device->id + , pCCB->pcmd->device->lun + , pCCB); + pCCB->pcmd->result = DID_ABORT << 16; + arcmsr_ccb_complete(pCCB, 1); + poll_ccb_done = 1; + continue; + } + printk(KERN_NOTICE + "arcmsr%d: polling get an illegal ccb" + " command done ccb='0x%p'" + "ccboutstandingcount=%d \n" + , pACB->adapter_index + , pCCB + , atomic_read(&pACB->ccboutstandingcount)); + continue; + } + id = pCCB->pcmd->device->id; + lun = pCCB->pcmd->device->lun; + if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { + if (pACB->devstate[id][lun] == ARECA_RAID_GONE) + pACB->devstate[id][lun] = ARECA_RAID_GOOD; + pCCB->pcmd->result = DID_OK << 16; + arcmsr_ccb_complete(pCCB, 1); + } else { + switch(pCCB->arcmsr_cdb.DeviceStatus) { + case ARCMSR_DEV_SELECT_TIMEOUT: { + pACB->devstate[id][lun] = ARECA_RAID_GONE; + pCCB->pcmd->result = DID_TIME_OUT << 16; + arcmsr_ccb_complete(pCCB, 1); + } + break; + case ARCMSR_DEV_ABORTED: + case ARCMSR_DEV_INIT_FAIL: { + pACB->devstate[id][lun] = ARECA_RAID_GONE; + pCCB->pcmd->result = DID_BAD_TARGET << 16; + arcmsr_ccb_complete(pCCB, 1); + } + break; + case SCSISTAT_CHECK_CONDITION: { + pACB->devstate[id][lun] = ARECA_RAID_GOOD; + arcmsr_report_sense_info(pCCB); + arcmsr_ccb_complete(pCCB, 1); + } + break; + default: + printk(KERN_NOTICE + "arcmsr%d: scsi id=%d lun=%d" + " polling and getting command error done" + "but got unknown DeviceStatus = 0x%x \n" + , pACB->adapter_index + , id + , lun + , pCCB->arcmsr_cdb.DeviceStatus); + pACB->devstate[id][lun] = ARECA_RAID_GONE; + pCCB->pcmd->result = DID_BAD_TARGET << 16; + arcmsr_ccb_complete(pCCB, 1); + break; + } + } + } +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_iop_init(struct ACB *pACB) +{ + struct MU __iomem *reg = pACB->pmu; + uint32_t intmask_org, mask, outbound_doorbell, firmware_state = 0; + + do { + firmware_state = readl(®->outbound_msgaddr1); + } while (!(firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK)); + intmask_org = readl(®->outbound_intmask) + | ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE; + arcmsr_get_firmware_spec(pACB); + arcmsr_start_adapter_bgrb(pACB); + outbound_doorbell = readl(®->outbound_doorbell); + writel(outbound_doorbell, ®->outbound_doorbell); + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); + mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE + | ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); + writel(intmask_org & mask, ®->outbound_intmask); + pACB->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff; + pACB->acb_flags |= ACB_F_IOP_INITED; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static int arcmsr_bus_reset(struct scsi_cmnd *cmd) +{ + struct ACB *pACB; + int retry = 0; + + pACB = (struct ACB *) cmd->device->host->hostdata; + printk(KERN_NOTICE "arcmsr%d: bus reset ..... \n", pACB->adapter_index); + pACB->num_resets++; + pACB->acb_flags |= ACB_F_BUS_RESET; + while (atomic_read(&pACB->ccboutstandingcount) != 0 && retry < 400) { + arcmsr_interrupt(pACB); + msleep(25); + retry++; + } + arcmsr_iop_reset(pACB); + pACB->acb_flags &= ~ACB_F_BUS_RESET; + return SUCCESS; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static int arcmsr_seek_cmd2abort(struct scsi_cmnd *abortcmd) +{ + struct ACB *pACB = (struct ACB *) abortcmd->device->host->hostdata; + struct MU __iomem *reg = pACB->pmu; + struct CCB *pCCB; + uint32_t intmask_org, mask; + int i = 0, pendingcount; + + pACB->num_aborts++; + /* + ***************************************************************** + ** It is the upper layer do abort command this lock just prior + ** to calling us. + ** First determine if we currently own this command. + ** Start by searching the device queue. If not found + ** at all, and the system wanted us to just abort the + ** command return success. + ***************************************************************** + */ + if (atomic_read(&pACB->ccboutstandingcount) != 0) { + for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { + pCCB = pACB->pccb_pool[i]; + if (pCCB->startdone == ARCMSR_CCB_START) { + if (pCCB->pcmd == abortcmd) { + pCCB->startdone = ARCMSR_CCB_ABORTED; + printk(KERN_NOTICE + "arcmsr%d: scsi id=%d lun=%d" + " abort ccb '0x%p' outstanding command\n" + , pACB->adapter_index + , abortcmd->device->id + , abortcmd->device->lun + , pCCB); + goto abort_outstanding_cmd; + } + } + } + } + /* + ********************************************************** + ** seek this command at our command list + ** if command found then remove, abort it and free this CCB + ********************************************************** + */ + pendingcount = atomic_read(&pACB->ccbpendingcount); + if (pendingcount > 0) { + do { + pCCB = arcmsr_get_pendingccb(pACB); + if (!pCCB) + break; + if (pCCB->pcmd == abortcmd) { + printk(KERN_NOTICE + "arcmsr%d: scsi id=%d lun=%d" + " abort ccb '0x%p' pending command \n" + , pACB->adapter_index + , abortcmd->device->id + , abortcmd->device->lun + , pCCB); + pCCB->startdone = ARCMSR_CCB_ABORTED; + pCCB->pcmd->result = DID_ABORT << 16; + arcmsr_ccb_complete(pCCB, 0); + return SUCCESS; + } else + arcmsr_queue_pendingccb(pACB, pCCB); + } while (pendingcount--); + } + return SUCCESS; +abort_outstanding_cmd: + /*wait for 3 sec for all command done*/ + msleep_interruptible(3000); + /* disable all outbound interrupt */ + intmask_org = readl(®->outbound_intmask); + writel(intmask_org | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE + , ®->outbound_intmask); + arcmsr_polling_ccbdone(pACB, pCCB); + /* enable all outbound interrupt */ + mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE + | ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); + writel(intmask_org & mask, ®->outbound_intmask); + return SUCCESS; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static int arcmsr_cmd_abort(struct scsi_cmnd *cmd) +{ + struct ACB *pACB = (struct ACB *) cmd->device->host->hostdata; + int error; + + printk(KERN_NOTICE + "arcmsr%d: abort device command of scsi id=%d lun=%d \n" + , pACB->adapter_index + , cmd->device->id + , cmd->device->lun); + /* + ************************************************ + ** the all interrupt service routine is locked + ** we need to handle it as soon as possible and exit + ************************************************ + */ + error = arcmsr_seek_cmd2abort(cmd); + if (error != SUCCESS) + printk(KERN_NOTICE + "arcmsr%d: abort command failed scsi id=%d lun=%d \n" + , pACB->adapter_index + , cmd->device->id + , cmd->device->lun); + return error; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static const char *arcmsr_info(struct Scsi_Host *host) +{ + static char buf[256]; + struct ACB *pACB; + uint16_t device_id; + + pACB = (struct ACB *) host->hostdata; + device_id = pACB->pci_device->device; + switch(device_id) { + case PCIDeviceIDARC1110: { + sprintf(buf, + "ARECA ARC1110 PCI-X 4 PORTS SATA RAID CONTROLLER " + "\n %s" + , ARCMSR_DRIVER_VERSION); + break; + } + case PCIDeviceIDARC1120: { + sprintf(buf, + "ARECA ARC1120 PCI-X 8 PORTS SATA RAID CONTROLLER " + "(RAID6-ENGINE Inside)\n %s" + , ARCMSR_DRIVER_VERSION); + break; + } + case PCIDeviceIDARC1130: { + sprintf(buf, + "ARECA ARC1130 PCI-X 12 PORTS SATA RAID CONTROLLER " + "(RAID6-ENGINE Inside)\n %s" + , ARCMSR_DRIVER_VERSION); + break; + } + case PCIDeviceIDARC1160: { + sprintf(buf, + "ARECA ARC1160 PCI-X 16 PORTS SATA RAID CONTROLLER " + "(RAID6-ENGINE Inside)\n %s" + , ARCMSR_DRIVER_VERSION); + break; + } + case PCIDeviceIDARC1170: { + sprintf(buf, + "ARECA ARC1170 PCI-X 24 PORTS SATA RAID CONTROLLER " + "(RAID6-ENGINE Inside)\n %s" + , ARCMSR_DRIVER_VERSION); + break; + } + case PCIDeviceIDARC1210: { + sprintf(buf, + "ARECA ARC1210 PCI-EXPRESS 4 PORTS SATA RAID CONTROLLER " + "\n %s" + , ARCMSR_DRIVER_VERSION); + break; + } + case PCIDeviceIDARC1220: { + sprintf(buf, + "ARECA ARC1220 PCI-EXPRESS 8 PORTS SATA RAID CONTROLLER " + "(RAID6-ENGINE Inside)\n %s" + , ARCMSR_DRIVER_VERSION); + break; + } + case PCIDeviceIDARC1230: { + sprintf(buf, + "ARECA ARC1230 PCI-EXPRESS 12 PORTS SATA RAID CONTROLLER " + "(RAID6-ENGINE Inside)\n %s" + , ARCMSR_DRIVER_VERSION); + break; + } + case PCIDeviceIDARC1260: { + sprintf(buf, + "ARECA ARC1260 PCI-EXPRESS 16 PORTS SATA RAID CONTROLLER " + "(RAID6-ENGINE Inside)\n %s" + , ARCMSR_DRIVER_VERSION); + break; + } + case PCIDeviceIDARC1270: { + sprintf(buf, + "ARECA ARC1270 PCI-EXPRESS 24 PORTS SATA RAID CONTROLLER " + "(RAID6-ENGINE Inside)\n %s" + , ARCMSR_DRIVER_VERSION); + break; + } + case PCIDeviceIDARC1280: + default: { + sprintf(buf, + "ARECA X-TYPE SATA RAID CONTROLLER " + "(RAID6-ENGINE Inside)\n %s" + , ARCMSR_DRIVER_VERSION); + break; + } + } + return buf; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static int arcmsr_initialize(struct ACB *pACB, struct pci_dev *pci_device) +{ + struct MU __iomem *reg; + uint32_t intmask_org, ccb_phyaddr_hi32; + dma_addr_t dma_coherent_handle, dma_addr; + struct HCBARC *pHCBARC = &arcmsr_host_control_block; + uint8_t pcicmd; + void *dma_coherent; + void __iomem *page_remapped; + int i, j; + struct CCB *pccb_tmp; + + pci_read_config_byte(pci_device, PCI_COMMAND, &pcicmd); + pci_write_config_byte(pci_device, PCI_COMMAND, + pcicmd | PCI_COMMAND_INVALIDATE | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); + page_remapped = ioremap(pci_resource_start(pci_device, 0), + pci_resource_len(pci_device, 0)); + if ( !page_remapped ) { + printk(KERN_NOTICE "arcmsr%d: memory" + " mapping region fail \n", arcmsr_adapterCnt); + return -ENXIO; + } + pACB->pmu = (struct MU __iomem *)(page_remapped); + pACB->acb_flags |= + (ACB_F_IOCTL_WQBUFFER_CLEARED + | ACB_F_IOCTL_RQBUFFER_CLEARED + | ACB_F_IOCTL_WQBUFFER_READED); + pACB->acb_flags &= ~ACB_F_SCSISTOPADAPTER; + pACB->irq = pci_device->irq; + INIT_LIST_HEAD(&pACB->ccb_free_list); + INIT_LIST_HEAD(&pACB->ccb_pending_list); + dma_coherent = dma_alloc_coherent(&pci_device->dev + , ARCMSR_MAX_FREECCB_NUM * sizeof (struct CCB) + 0x20 + , &dma_coherent_handle, GFP_KERNEL); + if (!dma_coherent) { + printk(KERN_NOTICE + "arcmsr%d: dma_alloc_coherent got error \n" + , arcmsr_adapterCnt); + return -ENOMEM; + } + pACB->dma_coherent = dma_coherent; + pACB->dma_coherent_handle = dma_coherent_handle; + memset(dma_coherent, 0, ARCMSR_MAX_FREECCB_NUM * sizeof (struct CCB) + 0x20); + if (((unsigned long)dma_coherent & 0x1F) != 0) { + 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; + pccb_tmp = (struct CCB *)dma_coherent; + for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { + pccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5; + pccb_tmp->pACB = pACB; + pACB->pccb_pool[i] = pccb_tmp; + list_add_tail(&pccb_tmp->list, &pACB->ccb_free_list); + dma_addr = dma_addr + sizeof (struct CCB); + pccb_tmp++; + } + pACB->vir2phy_offset = (unsigned long)pccb_tmp - (unsigned long)dma_addr; + for(i = 0; i < ARCMSR_MAX_TARGETID; i++) { + for(j = 0; j < ARCMSR_MAX_TARGETLUN; j++) + pACB->devstate[i][j] = ARECA_RAID_GOOD; + } + reg = pACB->pmu; + /* + ************************************************************* + ** here we need to tell iop 331 our pccb_tmp.HighPart + ** if pccb_tmp.HighPart is not zero + ************************************************************* + */ + ccb_phyaddr_hi32 = (uint32_t) ((dma_coherent_handle >> 16) >> 16); + if (ccb_phyaddr_hi32 != 0) { + writel(ARCMSR_SIGNATURE_SET_CONFIG, ®->message_rwbuffer[0]); + writel(ccb_phyaddr_hi32, ®->message_rwbuffer[1]); + writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0); + if (arcmsr_wait_msgint_ready(pACB)) + printk(KERN_NOTICE + "arcmsr%d: 'set ccb high part physical address' timeout \n" + , arcmsr_adapterCnt); + } + pACB->adapter_index = arcmsr_adapterCnt; + pHCBARC->pACB[arcmsr_adapterCnt] = pACB; + intmask_org = readl(®->outbound_intmask); + writel(intmask_org | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE + , ®->outbound_intmask); + arcmsr_adapterCnt++; + return 0; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static int arcmsr_set_info(char *buffer, int length) +{ + return 0; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static void arcmsr_pcidev_disattach(struct ACB *pACB) +{ + struct MU __iomem *reg = pACB->pmu; + struct pci_dev *pci_device; + struct CCB *pCCB; + struct HCBARC *pHCBARC = &arcmsr_host_control_block; + struct Scsi_Host *host; + uint32_t intmask_org; + int i = 0, poll_count = 0, have_msi = 0; + + arcmsr_stop_adapter_bgrb(pACB); + arcmsr_flush_adapter_cache(pACB); + intmask_org = readl(®->outbound_intmask); + writel(intmask_org | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE + , ®->outbound_intmask); + pACB->acb_flags |= ACB_F_SCSISTOPADAPTER; + pACB->acb_flags &= ~ACB_F_IOP_INITED; + if (atomic_read(&pACB->ccboutstandingcount) != 0) { + while (atomic_read(&pACB->ccboutstandingcount) != 0 && (poll_count < 256)) { + arcmsr_interrupt(pACB); + msleep(25); + poll_count++; + } + if (atomic_read(&pACB->ccboutstandingcount) != 0) { + arcmsr_abort_allcmd(pACB); + for(i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++) + readl(®->outbound_queueport); + for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { + pCCB = pACB->pccb_pool[i]; + if (pCCB->startdone == ARCMSR_CCB_START) { + pCCB->startdone = ARCMSR_CCB_ABORTED; + pCCB->pcmd->result = DID_ABORT << 16; + arcmsr_ccb_complete(pCCB, 1); + } + } + } + } + while (atomic_read(&pACB->ccbpendingcount) != 0) { + pCCB = arcmsr_get_pendingccb(pACB); + if (pCCB) { + pCCB->startdone = ARCMSR_CCB_ABORTED; + pCCB->pcmd->result = DID_ABORT << 16; + arcmsr_ccb_complete(pCCB, 0); + atomic_dec(&pACB->ccbpendingcount); + } else + break; + } + if ((pACB->acb_flags & ACB_F_HAVE_MSI) != 0) { + have_msi = 1; + } + host = pACB->host; + pci_device = pACB->pci_device; + iounmap(pACB->pmu); + arcmsr_free_ccb_pool(pACB); + pHCBARC->pACB[pACB->adapter_index] = NULL; + scsi_remove_host(host); + scsi_host_put(host); + free_irq(pci_device->irq, pACB); +#ifdef CONFIG_SCSI_ARCMSR_MSI + if (have_msi == 1) + pci_disable_msi(pci_device); +#endif + pci_release_regions(pci_device); + pci_disable_device(pci_device); + pci_set_drvdata(pci_device, NULL); +} +/* +******************************************************************************* +******************************************************************************* +*/ +static int arcmsr_halt_notify(struct notifier_block *nb, unsigned long event, void *buf) +{ + struct ACB *pACB; + struct HCBARC *pHCBARC = &arcmsr_host_control_block; + int i; + + if ((event != SYS_RESTART) && (event != SYS_HALT) && (event != SYS_POWER_OFF)) + return NOTIFY_DONE; + for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) { + pACB = pHCBARC->pACB[i]; + if (!pACB) + continue; + arcmsr_pcidev_disattach(pACB); + } + unregister_chrdev(pHCBARC->arcmsr_major_number, "arcmsr"); + unregister_reboot_notifier(&arcmsr_event_notifier); + return NOTIFY_OK; +} +/* +******************************************************************************* +******************************************************************************* +*/ +#undef SPRINTF +#define SPRINTF(args...) pos +=sprintf(pos,## args) +#define YESNO(YN)\ +if (YN) SPRINTF(" Yes ");\ +else SPRINTF(" No ") + +static int arcmsr_proc_info(struct Scsi_Host *host, char *buffer, + char **start, off_t offset, int length, int inout) +{ + uint8_t i; + struct HCBARC *pHCBARC = &arcmsr_host_control_block; + char * pos = buffer; + struct ACB *pACB; + + if (inout) + return(arcmsr_set_info(buffer, length)); + for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) { + pACB = pHCBARC->pACB[i]; + if (!pACB) + continue; + SPRINTF("ARECA SATA RAID Mass Storage Host Adadpter \n"); + SPRINTF("Driver Version %s ", ARCMSR_DRIVER_VERSION); + SPRINTF("IRQ%d \n", pACB->pci_device->irq); + SPRINTF("===========================\n"); + } + *start = buffer + offset; + if (pos - buffer < offset) + return 0; + else if (pos - buffer - offset < length) + return pos - buffer - offset; + return length; +} +/* +******************************************************************************* +******************************************************************************* +*/ +static int arcmsr_release(struct Scsi_Host *host) +{ + struct ACB *pACB; + struct HCBARC *pHCBARC = &arcmsr_host_control_block; + uint8_t match = 0xff, i; + + if (!host) + return -ENXIO; + pACB = (struct ACB *)host->hostdata; + if (!pACB) + return -ENXIO; + for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) { + if (pHCBARC->pACB[i] == pACB) + match = i; + } + if (match == 0xff) + return -ENXIO; + arcmsr_pcidev_disattach(pACB); + for(i = 0; i < ARCMSR_MAX_ADAPTER; i++) { + if (pHCBARC->pACB[i]) + return 0; + } + unregister_chrdev(pHCBARC->arcmsr_major_number, "arcmsr"); + unregister_reboot_notifier(&arcmsr_event_notifier); + return 0; +} + diff -puN /dev/null drivers/scsi/arcmsr/arcmsr.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ devel-akpm/drivers/scsi/arcmsr/arcmsr.h 2006-03-08 00:13:09.000000000 -0800 @@ -0,0 +1,1242 @@ +/* +******************************************************************************* +** O.S : Linux +** FILE NAME : arcmsr.h +** 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: erich@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. +******************************************************************************* +*/ +#define ARCMSR_MAX_OUTSTANDING_CMD 256 +#define ARCMSR_MAX_PENDING_CMD 64 +#define ARCMSR_MAX_FREECCB_NUM 320 +#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.13" +#define ARCMSR_SCSI_INITIATOR_ID 255 +#define ARCMSR_DEV_SECTOR_SIZE 512 +#define ARCMSR_MAX_XFER_SECTORS 256 +#define ARCMSR_MAX_XFER_LEN ARCMSR_MAX_XFER_SECTORS * ARCMSR_DEV_SECTOR_SIZE +#define ARCMSR_MAX_TARGETID 16 +#define ARCMSR_MAX_TARGETLUN 8 +#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD +#define ARCMSR_MAX_QBUFFER 4096 +#define ARCMSR_MAX_SG_ENTRIES 38 +#define ARCMSR_MAX_ADAPTER 4 +/* +******************************************************************************* +******************************************************************************* +*/ +#define PCIVendorIDARECA 0x17D3 /* Vendor ID */ +#define PCIDeviceIDARC1110 0x1110 /* Device ID */ +#define PCIDeviceIDARC1120 0x1120 /* Device ID */ +#define PCIDeviceIDARC1130 0x1130 /* Device ID */ +#define PCIDeviceIDARC1160 0x1160 /* Device ID */ +#define PCIDeviceIDARC1170 0x1170 /* Device ID */ +#define PCIDeviceIDARC1210 0x1210 /* Device ID */ +#define PCIDeviceIDARC1220 0x1220 /* Device ID */ +#define PCIDeviceIDARC1230 0x1230 /* Device ID */ +#define PCIDeviceIDARC1260 0x1260 /* Device ID */ +#define PCIDeviceIDARC1270 0x1270 /* Device ID */ +#define PCIDeviceIDARC1280 0x1280 /* Device ID */ +/* +******************************************************************************* +******************************************************************************* +*/ +#define dma_addr_hi32(addr) (uint32_t) ((addr>>16)>>16) +#define dma_addr_lo32(addr) (uint32_t) (addr & 0xffffffff) +/* +******************************************************************************* +** IOCTL CONTROL CODE +******************************************************************************* +*/ +struct CMD_IO_CONTROL +{ + uint32_t HeaderLength; + uint8_t Signature[8]; + uint32_t Timeout; + uint32_t ControlCode; + uint32_t ReturnCode; + uint32_t Length; +}; +/* +******************************************************************************* +******************************************************************************* +*/ +struct CMD_IOCTL_FIELD +{ + struct CMD_IO_CONTROL cmdioctl; + uint8_t ioctldatabuffer[1032]; +}; + +#define ARCMSR_IOP_ERROR_ILLEGALPCI 0x0001 +#define ARCMSR_IOP_ERROR_VENDORID 0x0002 +#define ARCMSR_IOP_ERROR_DEVICEID 0x0002 +#define ARCMSR_IOP_ERROR_ILLEGALCDB 0x0003 +#define ARCMSR_IOP_ERROR_UNKNOW_CDBERR 0x0004 +#define ARCMSR_SYS_ERROR_MEMORY_ALLOCATE 0x0005 +#define ARCMSR_SYS_ERROR_MEMORY_CROSS4G 0x0006 +#define ARCMSR_SYS_ERROR_MEMORY_LACK 0x0007 +#define ARCMSR_SYS_ERROR_MEMORY_RANGE 0x0008 +#define ARCMSR_SYS_ERROR_DEVICE_BASE 0x0009 +#define ARCMSR_SYS_ERROR_PORT_VALIDATE 0x000A +/*DeviceType*/ +#define ARECA_SATA_RAID 0x90000000 +/*FunctionCode*/ +#define FUNCTION_READ_RQBUFFER 0x0801 +#define FUNCTION_WRITE_WQBUFFER 0x0802 +#define FUNCTION_CLEAR_RQBUFFER 0x0803 +#define FUNCTION_CLEAR_WQBUFFER 0x0804 +#define FUNCTION_CLEAR_ALLQBUFFER 0x0805 +#define FUNCTION_RETURN_CODE_3F 0x0806 +#define FUNCTION_SAY_HELLO 0x0807 +#define FUNCTION_SAY_GOODBYE 0x0808 +#define FUNCTION_FLUSH_ADAPTER_CACHE 0x0809 +/* ARECA IO CONTROL CODE*/ +#define ARCMSR_IOCTL_READ_RQBUFFER \ + ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER +#define ARCMSR_IOCTL_WRITE_WQBUFFER \ + ARECA_SATA_RAID | FUNCTION_WRITE_WQBUFFER +#define ARCMSR_IOCTL_CLEAR_RQBUFFER \ + ARECA_SATA_RAID | FUNCTION_CLEAR_RQBUFFER +#define ARCMSR_IOCTL_CLEAR_WQBUFFER \ + ARECA_SATA_RAID | FUNCTION_CLEAR_WQBUFFER +#define ARCMSR_IOCTL_CLEAR_ALLQBUFFER \ + ARECA_SATA_RAID | FUNCTION_CLEAR_ALLQBUFFER +#define ARCMSR_IOCTL_RETURN_CODE_3F \ + ARECA_SATA_RAID | FUNCTION_RETURN_CODE_3F +#define ARCMSR_IOCTL_SAY_HELLO \ + ARECA_SATA_RAID | FUNCTION_SAY_HELLO +#define ARCMSR_IOCTL_SAY_GOODBYE \ + ARECA_SATA_RAID | FUNCTION_SAY_GOODBYE +#define ARCMSR_IOCTL_FLUSH_ADAPTER_CACHE \ + ARECA_SATA_RAID | FUNCTION_FLUSH_ADAPTER_CACHE +/* ARECA IOCTL ReturnCode */ +#define ARCMSR_IOCTL_RETURNCODE_OK 0x00000001 +#define ARCMSR_IOCTL_RETURNCODE_ERROR 0x00000006 +#define ARCMSR_IOCTL_RETURNCODE_3F 0x0000003F +/* +************************************************************* +** structure for holding DMA address data +************************************************************* +*/ +#define IS_SG64_ADDR 0x01000000 /* bit24 */ +struct SG32ENTRY +{ + uint32_t length; + uint32_t address; +}; +struct SG64ENTRY +{ + uint32_t length; + uint32_t address; + uint32_t addresshigh; +}; +struct SGENTRY_UNION +{ + union + { + struct SG32ENTRY sg32entry; + struct SG64ENTRY sg64entry; + }u; +}; +/* +********************************** +********************************** +*/ +struct QBUFFER +{ + uint32_t data_len; + uint8_t data[124]; +}; +/* +******************************************************************************* +** FIRMWARE INFO +******************************************************************************* +*/ +struct FIRMWARE_INFO +{ + uint32_t signature; /*0, 00-03*/ + uint32_t request_len; /*1, 04-07*/ + uint32_t numbers_queue; /*2, 08-11*/ + uint32_t sdram_size; /*3, 12-15*/ + uint32_t ide_channels; /*4, 16-19*/ + char vendor[40]; /*5, 20-59*/ + char model[8]; /*15, 60-67*/ + char firmware_ver[16]; /*17, 68-83*/ + char device_map[16]; /*21, 84-99*/ +}; +/* +******************************************************************************* +** ARECA FIRMWARE SPEC +******************************************************************************* +** Usage of IOP331 adapter +** (All In/Out is in IOP331's view) +** 1. Message 0 --> InitThread message and retrun code +** 2. Doorbell is used for RS-232 emulation +** inDoorBell : bit0 -- data in ready +** (DRIVER DATA WRITE OK) +** bit1 -- data out has been read +** (DRIVER DATA READ OK) +** outDooeBell: bit0 -- data out ready +** (IOP331 DATA WRITE OK) +** bit1 -- data in has been read +** (IOP331 DATA READ OK) +** 3. Index Memory Usage +** offset 0xf00 : for RS232 out (request buffer) +** offset 0xe00 : for RS232 in (scratch buffer) +** offset 0xa00 : for inbound message code message_rwbuffer +** (driver send to IOP331) +** offset 0xa00 : for outbound message code message_rwbuffer +** (IOP331 send to driver) +** 4. RS-232 emulation +** Currently 128 byte buffer is used +** 1st uint32_t : Data length (1--124) +** Byte 4--127 : Max 124 bytes of data +** 5. PostQ +** All SCSI Command must be sent through postQ: +** (inbound queue port) Request frame must be 32 bytes aligned +** #bit27--bit31 => flag for post ccb +** #bit0--bit26 => real address (bit27--bit31) of post arcmsr_cdb +** bit31 : +** 0 : 256 bytes frame +** 1 : 512 bytes frame +** bit30 : +** 0 : normal request +** 1 : BIOS request +** bit29 : reserved +** bit28 : reserved +** bit27 : reserved +** --------------------------------------------------------------------------- +** (outbount queue port) Request reply +** #bit27--bit31 +** => flag for reply +** #bit0--bit26 +** => real address (bit27--bit31) of reply arcmsr_cdb +** bit31 : must be 0 (for this type of reply) +** bit30 : reserved for BIOS handshake +** bit29 : reserved +** bit28 : +** 0 : no error, ignore AdapStatus/DevStatus/SenseData +** 1 : Error, error code in AdapStatus/DevStatus/SenseData +** bit27 : reserved +** 6. BIOS request +** All BIOS request is the same with request from PostQ +** Except : +** Request frame is sent from configuration space +** offset: 0x78 : Request Frame (bit30 == 1) +** offset: 0x18 : writeonly to generate +** IRQ to IOP331 +** Completion of request: +** (bit30 == 0, bit28==err flag) +** 7. Definition of SGL entry (structure) +** 8. Message1 Out - Diag Status Code (????) +** 9. Message0 message code : +** 0x00 : NOP +** 0x01 : Get Config +** ->offset 0xa00 :for outbound message code message_rwbuffer +** (IOP331 send to driver) +** Signature 0x87974060(4) +** Request len 0x00000200(4) +** numbers of queue 0x00000100(4) +** SDRAM Size 0x00000100(4)-->256 MB +** IDE Channels 0x00000008(4) +** vendor 40 bytes char +** model 8 bytes char +** FirmVer 16 bytes char +** Device Map 16 bytes char +** FirmwareVersion DWORD <== Added for checking of +** new firmware capability +** 0x02 : Set Config +** ->offset 0xa00 :for inbound message code message_rwbuffer +** (driver send to IOP331) +** Signature 0x87974063(4) +** UPPER32 of Request Frame (4)-->Driver Only +** 0x03 : Reset (Abort all queued Command) +** 0x04 : Stop Background Activity +** 0x05 : Flush Cache +** 0x06 : Start Background Activity +** (re-start if background is halted) +** 0x07 : Check If Host Command Pending +** (Novell May Need This Function) +** 0x08 : Set controller time +** ->offset 0xa00 : for inbound message code message_rwbuffer +** (driver to IOP331) +** byte 0 : 0xaa <-- signature +** byte 1 : 0x55 <-- signature +** byte 2 : year (04) +** byte 3 : month (1..12) +** byte 4 : date (1..31) +** byte 5 : hour (0..23) +** byte 6 : minute (0..59) +** byte 7 : second (0..59) +******************************************************************************* +*/ +/* signature of set and get firmware config */ +#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060 +#define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063 +/* message code of inbound message register */ +#define ARCMSR_INBOUND_MESG0_NOP 0x00000000 +#define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001 +#define ARCMSR_INBOUND_MESG0_SET_CONFIG 0x00000002 +#define ARCMSR_INBOUND_MESG0_ABORT_CMD 0x00000003 +#define ARCMSR_INBOUND_MESG0_STOP_BGRB 0x00000004 +#define ARCMSR_INBOUND_MESG0_FLUSH_CACHE 0x00000005 +#define ARCMSR_INBOUND_MESG0_START_BGRB 0x00000006 +#define ARCMSR_INBOUND_MESG0_CHK331PENDING 0x00000007 +#define ARCMSR_INBOUND_MESG0_SYNC_TIMER 0x00000008 +/* doorbell interrupt generator */ +#define ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK 0x00000001 +#define ARCMSR_INBOUND_DRIVER_DATA_READ_OK 0x00000002 +#define ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK 0x00000001 +#define ARCMSR_OUTBOUND_IOP331_DATA_READ_OK 0x00000002 +/* ccb areca cdb flag */ +#define ARCMSR_CCBPOST_FLAG_SGL_BSIZE 0x80000000 +#define ARCMSR_CCBPOST_FLAG_IAM_BIOS 0x40000000 +#define ARCMSR_CCBREPLY_FLAG_IAM_BIOS 0x40000000 +#define ARCMSR_CCBREPLY_FLAG_ERROR 0x10000000 +/* outbound firmware ok */ +#define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000 +/* +******************************************************************************* +** size 0x1F8 (504) +******************************************************************************* +*/ +struct ARCMSR_CDB +{ + uint8_t Bus; + uint8_t TargetID; + uint8_t LUN; + uint8_t Function; + + uint8_t CdbLength; + uint8_t sgcount; + uint8_t Flags; +#define ARCMSR_CDB_FLAG_SGL_BSIZE 0x01 +#define ARCMSR_CDB_FLAG_BIOS 0x02 +#define ARCMSR_CDB_FLAG_WRITE 0x04 +#define ARCMSR_CDB_FLAG_SIMPLEQ 0x00 +#define ARCMSR_CDB_FLAG_HEADQ 0x08 +#define ARCMSR_CDB_FLAG_ORDEREDQ 0x10 + uint8_t Reserved1; + + uint32_t Context; + uint32_t DataLength; + + uint8_t Cdb[16]; + + uint8_t DeviceStatus; +#define SCSISTAT_GOOD 0x00 +#define SCSISTAT_CHECK_CONDITION 0x02 +#define SCSISTAT_CONDITION_MET 0x04 +#define SCSISTAT_BUSY 0x08 +#define SCSISTAT_INTERMEDIATE 0x10 +#define SCSISTAT_INTERMEDIATE_COND_MET 0x14 +#define SCSISTAT_RESERVATION_CONFLICT 0x18 +#define SCSISTAT_COMMAND_TERMINATED 0x22 +#define SCSISTAT_QUEUE_FULL 0x28 +#define ARCMSR_DEV_SELECT_TIMEOUT 0xF0 +#define ARCMSR_DEV_ABORTED 0xF1 +#define ARCMSR_DEV_INIT_FAIL 0xF2 + uint8_t SenseData[15]; + + union + { + struct SG32ENTRY sg32entry[ARCMSR_MAX_SG_ENTRIES]; + struct SG64ENTRY sg64entry[ARCMSR_MAX_SG_ENTRIES]; + } u; +}; +/* +******************************************************************************* +** Messaging Unit (MU) of the Intel R 80331 I/O processor (80331) +******************************************************************************* +*/ +struct MU +{ + uint32_t resrved0[4]; /*0000 000F*/ + uint32_t inbound_msgaddr0; /*0010 0013*/ + uint32_t inbound_msgaddr1; /*0014 0017*/ + uint32_t outbound_msgaddr0; /*0018 001B*/ + uint32_t outbound_msgaddr1; /*001C 001F*/ + uint32_t inbound_doorbell; /*0020 0023*/ + uint32_t inbound_intstatus; /*0024 0027*/ + uint32_t inbound_intmask; /*0028 002B*/ + uint32_t outbound_doorbell; /*002C 002F*/ + uint32_t outbound_intstatus; /*0030 0033*/ + uint32_t outbound_intmask; /*0034 0037*/ + uint32_t reserved1[2]; /*0038 003F*/ + uint32_t inbound_queueport; /*0040 0043*/ + uint32_t outbound_queueport; /*0044 0047*/ + uint32_t reserved2[2]; /*0048 004F*/ + uint32_t reserved3[492]; /*0050 07FF 492*/ + uint32_t reserved4[128]; /*0800 09FF 128*/ + uint32_t message_rwbuffer[256]; /*0a00 0DFF 256*/ + uint32_t ioctl_wbuffer[32]; /*0E00 0E7F 32*/ + uint32_t reserved5[32]; /*0E80 0EFF 32*/ + uint32_t ioctl_rbuffer[32]; /*0F00 0F7F 32*/ + uint32_t reserved6[32]; /*0F80 0FFF 32*/ +}; +/* +******************************************************************************* +** Adapter Control Block +******************************************************************************* +*/ +struct ACB +{ + struct pci_dev * pci_device; + struct Scsi_Host * host; + unsigned long vir2phy_offset; + /* Offset is used in making arc cdb physical to virtual calculations */ + uint32_t outbound_int_enable; + + struct MU __iomem * pmu; + /* message unit ATU inbound base address0 */ + + uint8_t adapter_index; + uint8_t irq; + uint16_t acb_flags; +#define ACB_F_SCSISTOPADAPTER 0x0001 +#define ACB_F_MSG_STOP_BGRB 0x0002 + /* stop RAID background rebuild */ +#define ACB_F_MSG_START_BGRB 0x0004 + /* stop RAID background rebuild */ +#define ACB_F_IOPDATA_OVERFLOW 0x0008 + /* iop ioctl data rqbuffer overflow */ +#define ACB_F_IOCTL_WQBUFFER_CLEARED 0x0010 + /* ioctl clear wqbuffer */ +#define ACB_F_IOCTL_RQBUFFER_CLEARED 0x0020 + /* ioctl clear rqbuffer */ +#define ACB_F_IOCTL_WQBUFFER_READED 0x0040 +#define ACB_F_BUS_RESET 0x0080 +#define ACB_F_IOP_INITED 0x0100 + /* iop init */ +#define ACB_F_HAVE_MSI 0x0200 + /* pci message signal interrupt */ + + struct CCB * pccb_pool[ARCMSR_MAX_FREECCB_NUM]; + /* used for memory free */ + struct list_head ccb_free_list; + /* head of free ccb list */ + struct list_head ccb_pending_list; + /* head of pending ccb list */ + atomic_t ccboutstandingcount; + atomic_t ccbpendingcount; + + void * dma_coherent; + /* dma_coherent used for memory free */ + dma_addr_t dma_coherent_handle; + /* dma_coherent_handle used for memory free */ + + uint8_t rqbuffer[ARCMSR_MAX_QBUFFER]; + /* data collection buffer for read from 80331 */ + int32_t rqbuf_firstindex; + /* first of read buffer */ + int32_t rqbuf_lastindex; + /* last of read buffer */ + uint8_t wqbuffer[ARCMSR_MAX_QBUFFER]; + /* data collection buffer for write to 80331 */ + int32_t wqbuf_firstindex; + /* first of write buffer */ + int32_t wqbuf_lastindex; + /* last of write buffer */ + spinlock_t qbuffer_lock; + spinlock_t pending_list_lock; + spinlock_t working_list_lock; + spinlock_t done_list_lock; + + uint8_t devstate[ARCMSR_MAX_TARGETID][ARCMSR_MAX_TARGETLUN]; + /* id0 ..... id15, lun0...lun7 */ +#define ARECA_RAID_GONE 0x55 +#define ARECA_RAID_GOOD 0xaa + uint32_t num_resets; + uint32_t num_aborts; + uint32_t firm_request_len; + uint32_t firm_numbers_queue; + uint32_t firm_sdram_size; + uint32_t firm_ide_channels; + char firm_model[12]; + char firm_version[20]; +};/* HW_DEVICE_EXTENSION */ +/* +******************************************************************************* +** Command Control Block +** this CCB length must be 32 bytes boundary +******************************************************************************* +*/ +struct CCB +{ + struct ARCMSR_CDB arcmsr_cdb; + /* + ** 0-503 (size of CDB=504): + ** arcmsr messenger scsi command descriptor size 504 bytes + */ + uint32_t cdb_shifted_phyaddr; + /* 504-507 */ + uint32_t reserved1; + /* 508-511 */ +#if BITS_PER_LONG == 64 + /* ======================512+64 bytes======================== */ + struct list_head list; + /* 512-527 16 bytes next/prev ptrs for ccb lists */ + struct scsi_cmnd * pcmd; + /* 528-535 8 bytes pointer of linux scsi command */ + struct ACB * pACB; + /* 536-543 8 bytes pointer of acb */ + + uint16_t ccb_flags; + /* 544-545 */ + #define CCB_FLAG_READ 0x0000 + #define CCB_FLAG_WRITE 0x0001 + #define CCB_FLAG_ERROR 0x0002 + #define CCB_FLAG_FLUSHCACHE 0x0004 + #define CCB_FLAG_MASTER_ABORTED 0x0008 + uint16_t startdone; + /* 546-547 */ + #define ARCMSR_CCB_DONE 0x0000 + #define ARCMSR_CCB_START 0x55AA + #define ARCMSR_CCB_ABORTED 0xAA55 + #define ARCMSR_CCB_ILLEGAL 0xFFFF + uint32_t reserved2[7]; + /* 548-551 552-555 556-559 560-563 564-567 568-571 572-575 */ +#else + /* ======================512+32 bytes======================== */ + struct list_head list; + /* 512-519 8 bytes next/prev ptrs for ccb lists */ + struct scsi_cmnd * pcmd; + /* 520-523 4 bytes pointer of linux scsi command */ + struct ACB * pACB; + /* 524-527 4 bytes pointer of acb */ + + uint16_t ccb_flags; + /* 528-529 */ + #define CCB_FLAG_READ 0x0000 + #define CCB_FLAG_WRITE 0x0001 + #define CCB_FLAG_ERROR 0x0002 + #define CCB_FLAG_FLUSHCACHE 0x0004 + #define CCB_FLAG_MASTER_ABORTED 0x0008 + uint16_t startdone; + /* 530-531 */ + #define ARCMSR_CCB_DONE 0x0000 + #define ARCMSR_CCB_START 0x55AA + #define ARCMSR_CCB_ABORTED 0xAA55 + #define ARCMSR_CCB_ILLEGAL 0xFFFF + uint32_t reserved2[3]; + /* 532-535 536-539 540-543 */ +#endif + /* ========================================================== */ +}; +/* +********************************************************************* +********************************************************************* +*/ +struct HCBARC +{ + struct ACB * pACB[ARCMSR_MAX_ADAPTER]; + + int32_t arcmsr_major_number; + + uint8_t adapterCnt; + uint8_t reserved[3]; +}; +/* +******************************************************************************* +******************************************************************************* +*/ +struct SENSE_DATA +{ + uint8_t ErrorCode:7; +#define SCSI_SENSE_CURRENT_ERRORS 0x70 +#define SCSI_SENSE_DEFERRED_ERRORS 0x71 + uint8_t Valid:1; + uint8_t SegmentNumber; + uint8_t SenseKey:4; + uint8_t Reserved:1; + uint8_t IncorrectLength:1; + uint8_t EndOfMedia:1; + uint8_t FileMark:1; + uint8_t Information[4]; + uint8_t AdditionalSenseLength; + uint8_t CommandSpecificInformation[4]; + uint8_t AdditionalSenseCode; + uint8_t AdditionalSenseCodeQualifier; + uint8_t FieldReplaceableUnitCode; + uint8_t SenseKeySpecific[3]; +}; +/* +******************************************************************************* +** Peripheral Device Type definitions +******************************************************************************* +*/ +#define SCSI_DASD 0x00 /* Direct-access Device */ +#define SCSI_SEQACESS 0x01 /* Sequential-access device */ +#define SCSI_PRINTER 0x02 /* Printer device */ +#define SCSI_PROCESSOR 0x03 /* Processor device */ +#define SCSI_WRITEONCE 0x04 /* Write-once device */ +#define SCSI_CDROM 0x05 /* CD-ROM device */ +#define SCSI_SCANNER 0x06 /* Scanner device */ +#define SCSI_OPTICAL 0x07 /* Optical memory device */ +#define SCSI_MEDCHGR 0x08 /* Medium changer device */ +#define SCSI_COMM 0x09 /* Communications device */ +#define SCSI_NODEV 0x1F /* Unknown or no device type*/ +/* +******************************************************************************* +** 80331 PCI-to-PCI Bridge +** PCI Configuration Space +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_VENDORID_REG 0x00 /*word*/ +#define ARCMSR_PCI2PCI_DEVICEID_REG 0x02 /*word*/ +/* +******************************************************************************* +** 0x05-0x04 : command register +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_PRIMARY_COMMAND_REG 0x04 /*word*/ +#define PCI_DISABLE_INTERRUPT 0x0400 +/* +******************************************************************************* +** 0x07-0x06 : status register +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_PRIMARY_STATUS_REG 0x06 /*word: 06, 07 */ +#define ARCMSR_ADAP_66MHZ 0x20 +/* +******************************************************************************* +** 0x08 : revision ID +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_REVISIONID_REG 0x08 /*byte*/ +/* +******************************************************************************* +** 0x0b-0x09 : 0180_00 (class code 1, native pci mode ) +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_CLASSCODE_REG 0x09 /*3 bytes*/ +/* +******************************************************************************* +** 0x0c : cache line size +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_PRIMARY_CACHELINESIZE_REG 0x0C /*byte*/ +/* +******************************************************************************* +** 0x0d : latency timer (number of pci clock 00-ff ) +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_PRIMARY_LATENCYTIMER_REG 0x0D /*byte*/ +/* +******************************************************************************* +** 0x0e : (header type, single function ) +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_HEADERTYPE_REG 0x0E /*byte*/ +/* +******************************************************************************* +** 0x13-0x10 +** PCI CFG Base Address #0 (0x10) +******************************************************************************* +*/ +/* +******************************************************************************* +** 0x17-0x14 : +** PCI CFG Base Address #1 (0x14) +******************************************************************************* +*/ +/* +******************************************************************************* +** 0x1b-0x18 : +** PCI CFG Base Address #2 (0x18) +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_PRIMARY_BUSNUMBER_REG 0x18 +#define ARCMSR_PCI2PCI_SECONDARY_BUSNUMBER_REG 0x19 +#define ARCMSR_PCI2PCI_SUBORDINATE_BUSNUMBER_REG 0x1A +#define ARCMSR_PCI2PCI_SECONDARY_LATENCYTIMER_REG 0x1B +/* +******************************************************************************* +** 0x1f-0x1c : +** PCI CFG Base Address #3 (0x1C) +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_IO_BASE_REG 0x1C +#define ARCMSR_PCI2PCI_IO_LIMIT_REG 0x1D +#define ARCMSR_PCI2PCI_SECONDARY_STATUS_REG 0x1E +/* +******************************************************************************* +** 0x23-0x20 : +** PCI CFG Base Address #4 (0x20) +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_NONPREFETCHABLE_MEMORY_BASE_REG 0x20 +#define ARCMSR_PCI2PCI_NONPREFETCHABLE_MEMORY_LIMIT_REG 0x22 +/* +******************************************************************************* +** 0x27-0x24 : +** PCI CFG Base Address #5 (0x24) +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_PREFETCHABLE_MEMORY_BASE_REG 0x24 +#define ARCMSR_PCI2PCI_PREFETCHABLE_MEMORY_LIMIT_REG 0x26 +/* +******************************************************************************* +** 0x2b-0x28 : +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_PREFETCHABLE_MEMORY_BASE_UPPER32_REG 0x28 +/* +******************************************************************************* +** 0x2f-0x2c : +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_PREFETCHABLE_MEMORY_LIMIT_UPPER32_REG 0x2C +/* +******************************************************************************* +** 0x33-0x30 : +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_CAPABILITIES_POINTER_REG 0x34 +/* +******************************************************************************* +** 0x3b-0x35 : reserved +******************************************************************************* +*/ +/* +******************************************************************************* +** 0x3d-0x3c : +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_PRIMARY_INTERRUPT_LINE_REG 0x3C +#define ARCMSR_PCI2PCI_PRIMARY_INTERRUPT_PIN_REG 0x3D +/* +******************************************************************************* +** 0x3f-0x3e : +******************************************************************************* +*/ +#define ARCMSR_PCI2PCI_BRIDGE_CONTROL_REG 0x3E +/* +******************************************************************************* +** +******************************************************************************* +*/ +#define ARCMSR_ATU_VENDOR_ID_REG 0x00 +/* +******************************************************************************* +** ATU Device ID Register - ATUDID +******************************************************************************* +*/ +#define ARCMSR_ATU_DEVICE_ID_REG 0x02 +/* +******************************************************************************* +** ATU Command Register - ATUCMD +******************************************************************************* +*/ +#define ARCMSR_ATU_COMMAND_REG 0x04 +/* +******************************************************************************* +** ATU Status Register - ATUSR (Sheet 1 of 2) +******************************************************************************* +*/ +#define ARCMSR_ATU_STATUS_REG 0x06 +/* +******************************************************************************* +** ATU Revision ID Register - ATURID +******************************************************************************* +*/ +#define ARCMSR_ATU_REVISION_REG 0x08 +/* +******************************************************************************* +** ATU Class Code Register - ATUCCR +******************************************************************************* +*/ +#define ARCMSR_ATU_CLASS_CODE_REG 0x09 +/* +******************************************************************************* +** ATU Cacheline Size Register - ATUCLSR +******************************************************************************* +*/ +#define ARCMSR_ATU_CACHELINE_SIZE_REG 0x0C +/* +******************************************************************************* +** ATU Latency Timer Register - ATULT +******************************************************************************* +*/ +#define ARCMSR_ATU_LATENCY_TIMER_REG 0x0D +/* +******************************************************************************* +** ATU Header Type Register - ATUHTR +******************************************************************************* +*/ +#define ARCMSR_ATU_HEADER_TYPE_REG 0x0E +/* +******************************************************************************* +** ATU BIST Register - ATUBISTR +******************************************************************************* +*/ +#define ARCMSR_ATU_BIST_REG 0x0F +/* +******************************************************************************* +** Inbound ATU Base Address Register 0 - IABAR0 +******************************************************************************* +*/ +#define ARCMSR_INBOUND_ATU_BASE_ADDRESS0_REG 0x10 +#define ARCMSR_INBOUND_ATU_MEMORY_PREFETCHABLE 0x08 +#define ARCMSR_INBOUND_ATU_MEMORY_WINDOW64 0x04 +/* +******************************************************************************* +** +******************************************************************************* +*/ +#define ARCMSR_INBOUND_ATU_UPPER_BASE_ADDRESS0_REG 0x14 +/* +******************************************************************************* +** Inbound ATU Base Address Register 1 - IABAR1 +******************************************************************************* +*/ +#define ARCMSR_INBOUND_ATU_BASE_ADDRESS1_REG 0x18 +/* +******************************************************************************* +** Inbound ATU Upper Base Address Register 1 - IAUBAR1 +******************************************************************************* +*/ +#define ARCMSR_INBOUND_ATU_UPPER_BASE_ADDRESS1_REG 0x1C +/* +******************************************************************************* +** Inbound ATU Base Address Register 2 - IABAR2 +******************************************************************************* +*/ +#define ARCMSR_INBOUND_ATU_BASE_ADDRESS2_REG 0x20 +/* +******************************************************************************* +** Inbound ATU Upper Base Address Register 2 - IAUBAR2 +******************************************************************************* +*/ +#define ARCMSR_INBOUND_ATU_UPPER_BASE_ADDRESS2_REG 0x24 +/* +******************************************************************************* +** ATU Subsystem Vendor ID Register - ASVIR +******************************************************************************* +*/ +#define ARCMSR_ATU_SUBSYSTEM_VENDOR_ID_REG 0x2C +/* +******************************************************************************* +** ATU Subsystem ID Register - ASIR +******************************************************************************* +*/ +#define ARCMSR_ATU_SUBSYSTEM_ID_REG 0x2E +/* +******************************************************************************* +** Expansion ROM Base Address Register -ERBAR +******************************************************************************* +*/ +#define ARCMSR_EXPANSION_ROM_BASE_ADDRESS_REG 0x30 +#define ARCMSR_EXPANSION_ROM_ADDRESS_DECODE_ENABLE 0x01 +/* +******************************************************************************* +** ATU Capabilities Pointer Register - ATU_CAP_PTR +******************************************************************************* +*/ +#define ARCMSR_ATU_CAPABILITY_PTR_REG 0x34 +/* +******************************************************************************* +** ATU Interrupt Line Register - ATUILR +******************************************************************************* +*/ +#define ARCMSR_ATU_INTERRUPT_LINE_REG 0x3C +/* +******************************************************************************* +** ATU Interrupt Pin Register - ATUIPR +******************************************************************************* +*/ +#define ARCMSR_ATU_INTERRUPT_PIN_REG 0x3D +/* +******************************************************************************* +** ATU Minimum Grant Register - ATUMGNT +******************************************************************************* +*/ +#define ARCMSR_ATU_MINIMUM_GRANT_REG 0x3E +/* +******************************************************************************* +** ATU Maximum Latency Register - ATUMLAT +******************************************************************************* +*/ +#define ARCMSR_ATU_MAXIMUM_LATENCY_REG 0x3F +/* +******************************************************************************* +** Inbound ATU Limit Register 0 - IALR0 +******************************************************************************* +*/ +#define ARCMSR_INBOUND_ATU_LIMIT0_REG 0x40 +/* +******************************************************************************* +** Inbound ATU Translate Value Register 0 - IATVR0 +******************************************************************************* +*/ +#define ARCMSR_INBOUND_ATU_TRANSLATE_VALUE0_REG 0x44 +/* +******************************************************************************* +** Expansion ROM Limit Register - ERLR +******************************************************************************* +*/ +#define ARCMSR_EXPANSION_ROM_LIMIT_REG 0x48 +/* +******************************************************************************* +** Expansion ROM Translate Value Register - ERTVR +******************************************************************************* +*/ +#define ARCMSR_EXPANSION_ROM_TRANSLATE_VALUE_REG 0x4C +/* +******************************************************************************* +** Inbound ATU Limit Register 1 - IALR1 +******************************************************************************* +*/ +#define ARCMSR_INBOUND_ATU_LIMIT1_REG 0x50 +/* +******************************************************************************* +** Inbound ATU Limit Register 2 - IALR2 +******************************************************************************* +*/ +#define ARCMSR_INBOUND_ATU_LIMIT2_REG 0x54 +/* +******************************************************************************* +** Inbound ATU Translate Value Register 2 - IATVR2 +******************************************************************************* +*/ +#define ARCMSR_INBOUND_ATU_TRANSLATE_VALUE2_REG 0x58 +/* +******************************************************************************* +** Outbound I/O Window Translate Value Register - OIOWTVR +******************************************************************************* +*/ +#define ARCMSR_OUTBOUND_IO_WINDOW_TRANSLATE_VALUE_REG 0x5C +/* +******************************************************************************* +** Outbound Memory Window Translate Value Register 0 -OMWTVR0 +******************************************************************************* +*/ +#define ARCMSR_OUTBOUND_MEMORY_WINDOW_TRANSLATE_VALUE0_REG 0x60 +/* +******************************************************************************* +** Outbound Upper 32-bit Memory Window Translate Value Register 0 - OUMWTVR0 +******************************************************************************* +*/ +#define ARCMSR_OUTBOUND_UPPER32_MEMORY_WINDOW_TRANSLATE_VALUE0_REG 0x64 +/* +******************************************************************************* +** Outbound Memory Window Translate Value Register 1 -OMWTVR1 +******************************************************************************* +*/ +#define ARCMSR_OUTBOUND_MEMORY_WINDOW_TRANSLATE_VALUE1_REG 0x68 +/* +******************************************************************************* +** Outbound Upper 32-bit Memory Window Translate Value Register 1 - OUMWTVR1 +******************************************************************************* +*/ +#define ARCMSR_OUTBOUND_UPPER32_MEMORY_WINDOW_TRANSLATE_VALUE1_REG 0x6C +/* +******************************************************************************* +** Outbound Upper 32-bit Direct Window Translate Value Register - OUDWTVR +******************************************************************************* +*/ +#define ARCMSR_OUTBOUND_UPPER32_DIRECT_WINDOW_TRANSLATE_VALUE_REG 0x78 +/* +******************************************************************************* +** ATU Configuration Register - ATUCR +******************************************************************************* +*/ +#define ARCMSR_ATU_CONFIGURATION_REG 0x80 +/* +******************************************************************************* +** PCI Configuration and Status Register - PCSR +******************************************************************************* +*/ +#define ARCMSR_PCI_CONFIGURATION_STATUS_REG 0x84 +/* +******************************************************************************* +** ATU Interrupt Status Register - ATUISR +******************************************************************************* +*/ +#define ARCMSR_ATU_INTERRUPT_STATUS_REG 0x88 +/* +******************************************************************************* +** ATU Interrupt Mask Register - ATUIMR +******************************************************************************* +*/ +#define ARCMSR_ATU_INTERRUPT_MASK_REG 0x8C +/* +******************************************************************************* +** Inbound ATU Base Address Register 3 - IABAR3 +******************************************************************************* +*/ +#define ARCMSR_INBOUND_ATU_BASE_ADDRESS3_REG 0x90 +/* +******************************************************************************* +** Inbound ATU Upper Base Address Register 3 - IAUBAR3 +******************************************************************************* +*/ +#define ARCMSR_INBOUND_ATU_UPPER_BASE_ADDRESS3_REG 0x94 +/* +******************************************************************************* +** Inbound ATU Limit Register 3 - IALR3 +******************************************************************************* +*/ +#define ARCMSR_INBOUND_ATU_LIMIT3_REG 0x98 +/* +******************************************************************************* +** Inbound ATU Translate Value Register 3 - IATVR3 +******************************************************************************* +*/ +#define ARCMSR_INBOUND_ATU_TRANSLATE_VALUE3_REG 0x9C +/* +******************************************************************************* +** Outbound Configuration Cycle Address Register - OCCAR +******************************************************************************* +*/ +#define ARCMSR_OUTBOUND_CONFIGURATION_CYCLE_ADDRESS_REG 0xA4 +/* +******************************************************************************* +** Outbound Configuration Cycle Data Register - OCCDR +******************************************************************************* +*/ +#define ARCMSR_OUTBOUND_CONFIGURATION_CYCLE_DATA_REG 0xAC +/* +******************************************************************************* +** VPD Capability Identifier Register - VPD_CAPID +******************************************************************************* +*/ +#define ARCMSR_VPD_CAPABILITY_IDENTIFIER_REG 0xB8 +/* +******************************************************************************* +** VPD Next Item Pointer Register - VPD_NXTP +******************************************************************************* +*/ +#define ARCMSR_VPD_NEXT_ITEM_PTR_REG 0xB9 +/* +******************************************************************************* +** VPD Address Register - VPD_AR +******************************************************************************* +*/ +#define ARCMSR_VPD_ADDRESS_REG 0xBA +/* +******************************************************************************* +** VPD Data Register - VPD_DR +******************************************************************************* +*/ +#define ARCMSR_VPD_DATA_REG 0xBC +/* +******************************************************************************* +** Power Management Capability Identifier Register -PM_CAPID +******************************************************************************* +*/ +#define ARCMSR_POWER_MANAGEMENT_CAPABILITY_IDENTIFIER_REG 0xC0 +/* +******************************************************************************* +** Power Management Next Item Pointer Register - PM_NXTP +******************************************************************************* +*/ +#define ARCMSR_POWER_NEXT_ITEM_PTR_REG 0xC1 +/* +******************************************************************************* +** Power Management Capabilities Register - PM_CAP +******************************************************************************* +*/ +#define ARCMSR_POWER_MANAGEMENT_CAPABILITY_REG 0xC2 +/* +******************************************************************************* +** Power Management Control/Status Register - PM_CSR +******************************************************************************* +*/ +#define ARCMSR_POWER_MANAGEMENT_CONTROL_STATUS_REG 0xC4 +/* +******************************************************************************* +** PCI-X Capability Identifier Register - PX_CAPID +******************************************************************************* +*/ +#define ARCMSR_PCIX_CAPABILITY_IDENTIFIER_REG 0xE0 +/* +******************************************************************************* +** PCI-X Next Item Pointer Register - PX_NXTP +******************************************************************************* +*/ +#define ARCMSR_PCIX_NEXT_ITEM_PTR_REG 0xE1 +/* +******************************************************************************* +** PCI-X Command Register - PX_CMD +******************************************************************************* +*/ +#define ARCMSR_PCIX_COMMAND_REG 0xE2 +/* +******************************************************************************* +** PCI-X Status Register - PX_SR +******************************************************************************* +*/ +#define ARCMSR_PCIX_STATUS_REG 0xE4 +/* +******************************************************************************* +** Message Registers +******************************************************************************* +*/ +#define ARCMSR_MU_INBOUND_MESSAGE_REG0 0x10 +#define ARCMSR_MU_INBOUND_MESSAGE_REG1 0x14 +/* +******************************************************************************* +** Outbound Message Register - OMRx +******************************************************************************* +*/ +#define ARCMSR_MU_OUTBOUND_MESSAGE_REG0 0x18 +#define ARCMSR_MU_OUTBOUND_MESSAGE_REG1 0x1C +/* +******************************************************************************* +** Doorbell Registers +******************************************************************************* +*/ +#define ARCMSR_MU_INBOUND_DOORBELL_REG 0x20 +/* +******************************************************************************* +** Inbound Interrupt Status Register - IISR +******************************************************************************* +*/ +#define ARCMSR_MU_INBOUND_INTERRUPT_STATUS_REG0 0x24 +#define ARCMSR_MU_INBOUND_INDEX_INT 0x40 +#define ARCMSR_MU_INBOUND_QUEUEFULL_INT 0x20 +#define ARCMSR_MU_INBOUND_POSTQUEUE_INT 0x10 +#define ARCMSR_MU_INBOUND_ERROR_DOORBELL_INT 0x08 +#define ARCMSR_MU_INBOUND_DOORBELL_INT 0x04 +#define ARCMSR_MU_INBOUND_MESSAGE1_INT 0x02 +#define ARCMSR_MU_INBOUND_MESSAGE0_INT 0x01 +/* +******************************************************************************* +** Inbound Interrupt Mask Register - IIMR +******************************************************************************* +*/ +#define ARCMSR_MU_INBOUND_INTERRUPT_MASK_REG 0x28 +#define ARCMSR_MU_INBOUND_INDEX_INTMASKENABLE 0x40 +#define ARCMSR_MU_INBOUND_QUEUEFULL_INTMASKENABLE 0x20 +#define ARCMSR_MU_INBOUND_POSTQUEUE_INTMASKENABLE 0x10 +#define ARCMSR_MU_INBOUND_DOORBELL_ERROR_INTMASKENABLE 0x08 +#define ARCMSR_MU_INBOUND_DOORBELL_INTMASKENABLE 0x04 +#define ARCMSR_MU_INBOUND_MESSAGE1_INTMASKENABLE 0x02 +#define ARCMSR_MU_INBOUND_MESSAGE0_INTMASKENABLE 0x01 +/* +******************************************************************************* +** Outbound Doorbell Register - ODR +******************************************************************************* +*/ +#define ARCMSR_MU_OUTBOUND_DOORBELL_REG 0x2C +/* +******************************************************************************* +** Outbound Interrupt Status Register - OISR +******************************************************************************* +*/ +#define ARCMSR_MU_OUTBOUND_INTERRUPT_STATUS_REG 0x30 +#define ARCMSR_MU_OUTBOUND_PCI_INT 0x10 +#define ARCMSR_MU_OUTBOUND_POSTQUEUE_INT 0x08 +#define ARCMSR_MU_OUTBOUND_DOORBELL_INT 0x04 +#define ARCMSR_MU_OUTBOUND_MESSAGE1_INT 0x02 +#define ARCMSR_MU_OUTBOUND_MESSAGE0_INT 0x01 +#define ARCMSR_MU_OUTBOUND_HANDLE_INT \ + (ARCMSR_MU_OUTBOUND_MESSAGE0_INT \ + |ARCMSR_MU_OUTBOUND_MESSAGE1_INT \ + |ARCMSR_MU_OUTBOUND_DOORBELL_INT \ + |ARCMSR_MU_OUTBOUND_POSTQUEUE_INT \ + |ARCMSR_MU_OUTBOUND_PCI_INT) +/* +******************************************************************************* +** Outbound Interrupt Mask Register - OIMR +******************************************************************************* +*/ +#define ARCMSR_MU_OUTBOUND_INTERRUPT_MASK_REG 0x34 +#define ARCMSR_MU_OUTBOUND_PCI_INTMASKENABLE 0x10 +#define ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE 0x08 +#define ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE 0x04 +#define ARCMSR_MU_OUTBOUND_MESSAGE1_INTMASKENABLE 0x02 +#define ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE 0x01 +#define ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE 0x1F +/* +******************************************************************************* +** +******************************************************************************* +*/ +#define ARCMSR_MU_INBOUND_QUEUE_PORT_REG 0x40 +#define ARCMSR_MU_OUTBOUND_QUEUE_PORT_REG 0x44 + +/* +******************************************************************************* +** MU Configuration Register - MUCR FFFF.E350H +******************************************************************************* +*/ +#define ARCMSR_MU_CONFIGURATION_REG 0xFFFFE350 +#define ARCMSR_MU_CIRCULAR_QUEUE_SIZE64K 0x0020 +#define ARCMSR_MU_CIRCULAR_QUEUE_SIZE32K 0x0010 +#define ARCMSR_MU_CIRCULAR_QUEUE_SIZE16K 0x0008 +#define ARCMSR_MU_CIRCULAR_QUEUE_SIZE8K 0x0004 +#define ARCMSR_MU_CIRCULAR_QUEUE_SIZE4K 0x0002 +#define ARCMSR_MU_CIRCULAR_QUEUE_ENABLE 0x0001 +/* +******************************************************************************* +** Queue Base Address Register - QBAR +******************************************************************************* +*/ +#define ARCMSR_MU_QUEUE_BASE_ADDRESS_REG 0xFFFFE354 +/* +******************************************************************************* +** Inbound Free Head Pointer Register - IFHPR +******************************************************************************* +*/ +#define ARCMSR_MU_INBOUND_FREE_HEAD_PTR_REG 0xFFFFE360 +/* +******************************************************************************* +** Inbound Free Tail Pointer Register - IFTPR +******************************************************************************* +*/ +#define ARCMSR_MU_INBOUND_FREE_TAIL_PTR_REG 0xFFFFE364 +/* +******************************************************************************* +** Inbound Post Head Pointer Register - IPHPR +******************************************************************************* +*/ +#define ARCMSR_MU_INBOUND_POST_HEAD_PTR_REG 0xFFFFE368 +/* +******************************************************************************* +** Inbound Post Tail Pointer Register - IPTPR +******************************************************************************* +*/ +#define ARCMSR_MU_INBOUND_POST_TAIL_PTR_REG 0xFFFFE36C +/* +******************************************************************************* +** Index Address Register - IAR +******************************************************************************* +*/ +#define ARCMSR_MU_LOCAL_MEMORY_INDEX_REG 0xFFFFE380 diff -puN /dev/null drivers/scsi/arcmsr/Makefile --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ devel-akpm/drivers/scsi/arcmsr/Makefile 2006-03-08 00:13:09.000000000 -0800 @@ -0,0 +1,4 @@ +# File: drivers/arcmsr/Makefile +# Makefile for the ARECA PCI-X PCI-EXPRESS SATA RAID controllers SCSI driver. + +obj-$(CONFIG_SCSI_ARCMSR) := arcmsr.o diff -puN drivers/scsi/Kconfig~areca-raid-linux-scsi-driver drivers/scsi/Kconfig --- devel/drivers/scsi/Kconfig~areca-raid-linux-scsi-driver 2006-03-08 00:13:09.000000000 -0800 +++ devel-akpm/drivers/scsi/Kconfig 2006-03-08 00:13:09.000000000 -0800 @@ -459,6 +459,31 @@ config SCSI_IN2000 To compile this driver as a module, choose M here: the module will be called in2000. +config SCSI_ARCMSR + tristate "ARECA ARC11X0[PCI-X]/ARC12X0[PCI-EXPRESS] SATA-RAID support" + depends on PCI && SCSI + help + This driver supports all of ARECA's SATA RAID controller cards. + This is an ARECA-maintained driver by Erich Chen. + If you have any problems, please mail to: < erich@areca.com.tw > + Areca supports Linux RAID config tools. + + < http://www.areca.com.tw > + + To compile this driver as a module, choose M here: the + module will be called arcmsr (modprobe arcmsr). + +config SCSI_ARCMSR_MSI + bool "Use PCI message signal interrupt" + depends on PCI_MSI && SCSI_ARCMSR + default n + help + If you say Y here. You will enable PCI Message signaled Interrupts + function, but some machines may have problems. If you get + abort command on driver initialize, you have to answer Y here. + If the IRQ problem even worse, + please report the problem to the maintainer. + source "drivers/scsi/megaraid/Kconfig.megaraid" config SCSI_SATA diff -puN drivers/scsi/Makefile~areca-raid-linux-scsi-driver drivers/scsi/Makefile --- devel/drivers/scsi/Makefile~areca-raid-linux-scsi-driver 2006-03-08 00:13:09.000000000 -0800 +++ devel-akpm/drivers/scsi/Makefile 2006-03-08 00:13:09.000000000 -0800 @@ -58,6 +58,7 @@ obj-$(CONFIG_SCSI_PSI240I) += psi240i.o obj-$(CONFIG_SCSI_BUSLOGIC) += BusLogic.o obj-$(CONFIG_SCSI_DPT_I2O) += dpt_i2o.o obj-$(CONFIG_SCSI_U14_34F) += u14-34f.o +obj-$(CONFIG_SCSI_ARCMSR) += arcmsr/ obj-$(CONFIG_SCSI_ULTRASTOR) += ultrastor.o obj-$(CONFIG_SCSI_AHA152X) += aha152x.o obj-$(CONFIG_SCSI_AHA1542) += aha1542.o _