[SCSI] aacraid: Add new code for PMC-Sierra's SRC based controller family
authorMahesh Rajashekhara <Mahesh_Rajashekhara@pmc-sierra.com>
Thu, 17 Mar 2011 09:10:32 +0000 (02:10 -0700)
committerJames Bottomley <James.Bottomley@suse.de>
Wed, 23 Mar 2011 16:36:58 +0000 (11:36 -0500)
Added new hardware device 0x28b interface for PMC-Sierra's SRC based
controller family.

- new src.c file for 0x28b specific functions
- new XPORT header required
- sync. command interface: doorbell bits shifted (SRC_ODR_SHIFT, SRC_IDR_SHIFT)
- async. Interface: different inbound queue handling, no outbound I2O
  queue available, using doorbell ("PmDoorBellResponseSent") and
  response buffer on the host ("host_rrq") for status
- changed AIF (adapter initiated FIBs) interface: "DoorBellAifPending"
  bit to inform about pending AIF, "AifRequest" command to read AIF,
  "NoMoreAifDataAvailable" to mark the end of the AIFs

Signed-off-by: Mahesh Rajashekhara <aacraid@pmc-sierra.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
13 files changed:
drivers/scsi/aacraid/Makefile
drivers/scsi/aacraid/aachba.c
drivers/scsi/aacraid/aacraid.h
drivers/scsi/aacraid/commctrl.c
drivers/scsi/aacraid/comminit.c
drivers/scsi/aacraid/commsup.c
drivers/scsi/aacraid/dpcsup.c
drivers/scsi/aacraid/linit.c
drivers/scsi/aacraid/nark.c
drivers/scsi/aacraid/rkt.c
drivers/scsi/aacraid/rx.c
drivers/scsi/aacraid/sa.c
drivers/scsi/aacraid/src.c [new file with mode: 0644]

index 92df4d6b6147c677a76a4852bf521cd43ea88711..1bd9fd18f7f337eda4548c965c9f3d15e048dbaa 100644 (file)
@@ -3,6 +3,6 @@
 obj-$(CONFIG_SCSI_AACRAID) := aacraid.o
 
 aacraid-objs   := linit.o aachba.o commctrl.o comminit.o commsup.o \
-                  dpcsup.o rx.o sa.o rkt.o nark.o
+                  dpcsup.o rx.o sa.o rkt.o nark.o src.o
 
 ccflags-y      := -Idrivers/scsi
index 7df2dd1d2c6f8c014b10ad560d49c731e6477347..118ce83a737ce70ce0249a89b2f892921c5f3919 100644 (file)
@@ -5,7 +5,8 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2010 Adaptec, Inc.
+ *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -1486,7 +1487,9 @@ int aac_get_adapter_info(struct aac_dev* dev)
                        dev->a_ops.adapter_write = aac_write_block;
                }
                dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT;
-               if(!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) {
+               if (dev->adapter_info.options & AAC_OPT_NEW_COMM_TYPE1)
+                       dev->adapter_info.options |= AAC_OPT_NEW_COMM;
+               if (!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) {
                        /*
                         * Worst case size that could cause sg overflow when
                         * we break up SG elements that are larger than 64KB.
index 4dbcc055ac783bb4b8b3752def53a91dee759a7a..29ab00016b78e9d0118608746a033a2a8f107151 100644 (file)
@@ -12,7 +12,7 @@
  *----------------------------------------------------------------------------*/
 
 #ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 26400
+# define AAC_DRIVER_BUILD 28000
 # define AAC_DRIVER_BRANCH "-ms"
 #endif
 #define MAXIMUM_NUM_CONTAINERS 32
@@ -277,6 +277,16 @@ enum aac_queue_types {
 
 #define                FsaNormal       1
 
+/* transport FIB header (PMC) */
+struct aac_fib_xporthdr {
+       u64     HostAddress;    /* FIB host address w/o xport header */
+       u32     Size;           /* FIB size excluding xport header */
+       u32     Handle;         /* driver handle to reference the FIB */
+       u64     Reserved[2];
+};
+
+#define                ALIGN32         32
+
 /*
  * Define the FIB. The FIB is the where all the requested data and
  * command information are put to the application on the FSA adapter.
@@ -394,7 +404,9 @@ enum fib_xfer_state {
        AdapterMicroFib                 = (1<<17),
        BIOSFibPath                     = (1<<18),
        FastResponseCapable             = (1<<19),
-       ApiFib                          = (1<<20)       // Its an API Fib.
+       ApiFib                          = (1<<20),      /* Its an API Fib */
+       /* PMC NEW COMM: There is no more AIF data pending */
+       NoMoreAifDataAvailable          = (1<<21)
 };
 
 /*
@@ -404,6 +416,7 @@ enum fib_xfer_state {
 
 #define ADAPTER_INIT_STRUCT_REVISION           3
 #define ADAPTER_INIT_STRUCT_REVISION_4         4 // rocket science
+#define ADAPTER_INIT_STRUCT_REVISION_6         6 /* PMC src */
 
 struct aac_init
 {
@@ -428,9 +441,15 @@ struct aac_init
 #define INITFLAGS_NEW_COMM_SUPPORTED   0x00000001
 #define INITFLAGS_DRIVER_USES_UTC_TIME 0x00000010
 #define INITFLAGS_DRIVER_SUPPORTS_PM   0x00000020
+#define INITFLAGS_NEW_COMM_TYPE1_SUPPORTED     0x00000041
        __le32  MaxIoCommands;  /* max outstanding commands */
        __le32  MaxIoSize;      /* largest I/O command */
        __le32  MaxFibSize;     /* largest FIB to adapter */
+       /* ADAPTER_INIT_STRUCT_REVISION_5 begins here */
+       __le32  MaxNumAif;      /* max number of aif */
+       /* ADAPTER_INIT_STRUCT_REVISION_6 begins here */
+       __le32  HostRRQ_AddrLow;
+       __le32  HostRRQ_AddrHigh;       /* Host RRQ (response queue) for SRC */
 };
 
 enum aac_log_level {
@@ -685,7 +704,7 @@ struct rx_inbound {
 #define OutboundDoorbellReg    MUnit.ODR
 
 struct rx_registers {
-       struct rx_mu_registers          MUnit;          /* 1300h - 1344h */
+       struct rx_mu_registers          MUnit;          /* 1300h - 1347h */
        __le32                          reserved1[2];   /* 1348h - 134ch */
        struct rx_inbound               IndexRegs;
 };
@@ -703,7 +722,7 @@ struct rx_registers {
 #define rkt_inbound rx_inbound
 
 struct rkt_registers {
-       struct rkt_mu_registers         MUnit;           /* 1300h - 1344h */
+       struct rkt_mu_registers         MUnit;           /* 1300h - 1347h */
        __le32                          reserved1[1006]; /* 1348h - 22fch */
        struct rkt_inbound              IndexRegs;       /* 2300h - */
 };
@@ -713,6 +732,44 @@ struct rkt_registers {
 #define rkt_writeb(AEP, CSR, value)    writeb(value, &((AEP)->regs.rkt->CSR))
 #define rkt_writel(AEP, CSR, value)    writel(value, &((AEP)->regs.rkt->CSR))
 
+/*
+ * PMC SRC message unit registers
+ */
+
+#define src_inbound rx_inbound
+
+struct src_mu_registers {
+                               /*      PCI*| Name */
+       __le32  reserved0[8];   /*      00h | Reserved */
+       __le32  IDR;            /*      20h | Inbound Doorbell Register */
+       __le32  IISR;           /*      24h | Inbound Int. Status Register */
+       __le32  reserved1[3];   /*      28h | Reserved */
+       __le32  OIMR;           /*      34h | Outbound Int. Mask Register */
+       __le32  reserved2[25];  /*      38h | Reserved */
+       __le32  ODR_R;          /*      9ch | Outbound Doorbell Read */
+       __le32  ODR_C;          /*      a0h | Outbound Doorbell Clear */
+       __le32  reserved3[6];   /*      a4h | Reserved */
+       __le32  OMR;            /*      bch | Outbound Message Register */
+       __le32  IQ_L;           /*  c0h | Inbound Queue (Low address) */
+       __le32  IQ_H;           /*  c4h | Inbound Queue (High address) */
+};
+
+struct src_registers {
+       struct src_mu_registers MUnit;  /* 00h - c7h */
+       __le32 reserved1[130790];       /* c8h - 7fc5fh */
+       struct src_inbound IndexRegs;   /* 7fc60h */
+};
+
+#define src_readb(AEP, CSR)            readb(&((AEP)->regs.src.bar0->CSR))
+#define src_readl(AEP, CSR)            readl(&((AEP)->regs.src.bar0->CSR))
+#define src_writeb(AEP, CSR, value)    writeb(value, \
+                                               &((AEP)->regs.src.bar0->CSR))
+#define src_writel(AEP, CSR, value)    writel(value, \
+                                               &((AEP)->regs.src.bar0->CSR))
+
+#define SRC_ODR_SHIFT          12
+#define SRC_IDR_SHIFT          9
+
 typedef void (*fib_callback)(void *ctxt, struct fib *fibctx);
 
 struct aac_fib_context {
@@ -879,6 +936,7 @@ struct aac_supplement_adapter_info
 #define AAC_OPTION_MU_RESET            cpu_to_le32(0x00000001)
 #define AAC_OPTION_IGNORE_RESET                cpu_to_le32(0x00000002)
 #define AAC_OPTION_POWER_MANAGEMENT    cpu_to_le32(0x00000004)
+#define AAC_OPTION_DOORBELL_RESET      cpu_to_le32(0x00004000)
 #define AAC_SIS_VERSION_V3     3
 #define AAC_SIS_SLOT_UNKNOWN   0xFF
 
@@ -940,6 +998,7 @@ struct aac_bus_info_response {
 #define AAC_OPT_SUPPLEMENT_ADAPTER_INFO        cpu_to_le32(1<<16)
 #define AAC_OPT_NEW_COMM               cpu_to_le32(1<<17)
 #define AAC_OPT_NEW_COMM_64            cpu_to_le32(1<<18)
+#define AAC_OPT_NEW_COMM_TYPE1         cpu_to_le32(1<<28)
 
 struct aac_dev
 {
@@ -952,6 +1011,7 @@ struct aac_dev
         */
        unsigned                max_fib_size;
        unsigned                sg_tablesize;
+       unsigned                max_num_aif;
 
        /*
         *      Map for 128 fib objects (64k)
@@ -980,10 +1040,21 @@ struct aac_dev
        struct adapter_ops      a_ops;
        unsigned long           fsrev;          /* Main driver's revision number */
 
-       unsigned                base_size;      /* Size of mapped in region */
+       unsigned long           dbg_base;       /* address of UART
+                                                * debug buffer */
+
+       unsigned                base_size, dbg_size;    /* Size of
+                                                        *  mapped in region */
+
        struct aac_init         *init;          /* Holds initialization info to communicate with adapter */
        dma_addr_t              init_pa;        /* Holds physical address of the init struct */
 
+       u32                     *host_rrq;      /* response queue
+                                                * if AAC_COMM_MESSAGE_TYPE1 */
+
+       dma_addr_t              host_rrq_pa;    /* phys. address */
+       u32                     host_rrq_idx;   /* index into rrq buffer */
+
        struct pci_dev          *pdev;          /* Our PCI interface */
        void *                  printfbuf;      /* pointer to buffer used for printf's from the adapter */
        void *                  comm_addr;      /* Base address of Comm area */
@@ -1003,14 +1074,20 @@ struct aac_dev
         */
 #ifndef AAC_MIN_FOOTPRINT_SIZE
 #      define AAC_MIN_FOOTPRINT_SIZE 8192
+#      define AAC_MIN_SRC_BAR0_SIZE 0x400000
+#      define AAC_MIN_SRC_BAR1_SIZE 0x800
 #endif
        union
        {
                struct sa_registers __iomem *sa;
                struct rx_registers __iomem *rx;
                struct rkt_registers __iomem *rkt;
+               struct {
+                       struct src_registers __iomem *bar0;
+                       char __iomem *bar1;
+               } src;
        } regs;
-       volatile void __iomem *base;
+       volatile void __iomem *base, *dbg_base_mapped;
        volatile struct rx_inbound __iomem *IndexRegs;
        u32                     OIMR; /* Mask Register Cache */
        /*
@@ -1031,9 +1108,8 @@ struct aac_dev
        u8                      comm_interface;
 #      define AAC_COMM_PRODUCER 0
 #      define AAC_COMM_MESSAGE  1
-       /* macro side-effects BEWARE */
-#      define                  raw_io_interface \
-         init->InitStructRevision==cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4)
+#      define AAC_COMM_MESSAGE_TYPE1   3
+       u8                      raw_io_interface;
        u8                      raw_io_64;
        u8                      printf_enabled;
        u8                      in_reset;
@@ -1789,6 +1865,10 @@ extern struct aac_common aac_config;
 #define DoorBellAdapterNormCmdNotFull  (1<<3)  /* Adapter -> Host */
 #define DoorBellAdapterNormRespNotFull (1<<4)  /* Adapter -> Host */
 #define DoorBellPrintfReady            (1<<5)  /* Adapter -> Host */
+#define DoorBellAifPending             (1<<6)  /* Adapter -> Host */
+
+/* PMC specific outbound doorbell bits */
+#define PmDoorBellResponseSent         (1<<1)  /* Adapter -> Host */
 
 /*
  *     For FIB communication, we need all of the following things
@@ -1831,6 +1911,9 @@ extern struct aac_common aac_config;
 #define                AifReqAPIJobUpdate      109     /* Update a job report from the API */
 #define                AifReqAPIJobFinish      110     /* Finish a job from the API */
 
+/* PMC NEW COMM: Request the event data */
+#define                AifReqEvent             200
+
 /*
  *     Adapter Initiated FIB command structures. Start with the adapter
  *     initiated FIBs that really come from the adapter, and get responded
@@ -1886,10 +1969,13 @@ int aac_rx_init(struct aac_dev *dev);
 int aac_rkt_init(struct aac_dev *dev);
 int aac_nark_init(struct aac_dev *dev);
 int aac_sa_init(struct aac_dev *dev);
+int aac_src_init(struct aac_dev *dev);
 int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify);
 unsigned int aac_response_normal(struct aac_queue * q);
 unsigned int aac_command_normal(struct aac_queue * q);
-unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index);
+unsigned int aac_intr_normal(struct aac_dev *dev, u32 Index,
+                       int isAif, int isFastResponse,
+                       struct hw_fib *aif_fib);
 int aac_reset_adapter(struct aac_dev * dev, int forced);
 int aac_check_health(struct aac_dev * dev);
 int aac_command_thread(void *data);
index 645ddd9d9b9e1c702be4add64397f179cd2599d0..8a0b33033177174bca1766233ae596ae1f8e3ffa 100644 (file)
@@ -5,7 +5,8 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2010 Adaptec, Inc.
+ *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index a7261486ccd49cb20cfcaa7bb53d82c6f706be25..7ac8fdb5577b2cc922bb15a8737eea1ff3751cfa 100644 (file)
@@ -5,7 +5,8 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2010 Adaptec, Inc.
+ *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -52,12 +53,16 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
        unsigned long size, align;
        const unsigned long fibsize = 4096;
        const unsigned long printfbufsiz = 256;
+       unsigned long host_rrq_size = 0;
        struct aac_init *init;
        dma_addr_t phys;
        unsigned long aac_max_hostphysmempages;
 
-       size = fibsize + sizeof(struct aac_init) + commsize + commalign + printfbufsiz;
-
+       if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1)
+               host_rrq_size = (dev->scsi_host_ptr->can_queue
+                       + AAC_NUM_MGT_FIB) * sizeof(u32);
+       size = fibsize + sizeof(struct aac_init) + commsize +
+                       commalign + printfbufsiz + host_rrq_size;
  
        base = pci_alloc_consistent(dev->pdev, size, &phys);
 
@@ -70,8 +75,14 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
        dev->comm_phys = phys;
        dev->comm_size = size;
        
-       dev->init = (struct aac_init *)(base + fibsize);
-       dev->init_pa = phys + fibsize;
+       if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) {
+               dev->host_rrq = (u32 *)(base + fibsize);
+               dev->host_rrq_pa = phys + fibsize;
+               memset(dev->host_rrq, 0, host_rrq_size);
+       }
+
+       dev->init = (struct aac_init *)(base + fibsize + host_rrq_size);
+       dev->init_pa = phys + fibsize + host_rrq_size;
 
        init = dev->init;
 
@@ -106,8 +117,13 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
 
        init->InitFlags = 0;
        if (dev->comm_interface == AAC_COMM_MESSAGE) {
-               init->InitFlags = cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED);
+               init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED);
                dprintk((KERN_WARNING"aacraid: New Comm Interface enabled\n"));
+       } else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) {
+               init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_6);
+               init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_TYPE1_SUPPORTED);
+               dprintk((KERN_WARNING
+                       "aacraid: New Comm Interface type1 enabled\n"));
        }
        init->InitFlags |= cpu_to_le32(INITFLAGS_DRIVER_USES_UTC_TIME |
                                       INITFLAGS_DRIVER_SUPPORTS_PM);
@@ -115,11 +131,18 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
        init->MaxIoSize = cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9);
        init->MaxFibSize = cpu_to_le32(dev->max_fib_size);
 
+       init->MaxNumAif = cpu_to_le32(dev->max_num_aif);
+       init->HostRRQ_AddrHigh = (u32)((u64)dev->host_rrq_pa >> 32);
+       init->HostRRQ_AddrLow = (u32)(dev->host_rrq_pa & 0xffffffff);
+
+
        /*
         * Increment the base address by the amount already used
         */
-       base = base + fibsize + sizeof(struct aac_init);
-       phys = (dma_addr_t)((ulong)phys + fibsize + sizeof(struct aac_init));
+       base = base + fibsize + host_rrq_size + sizeof(struct aac_init);
+       phys = (dma_addr_t)((ulong)phys + fibsize + host_rrq_size +
+               sizeof(struct aac_init));
+
        /*
         *      Align the beginning of Headers to commalign
         */
@@ -314,15 +337,22 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
                - sizeof(struct aac_write) + sizeof(struct sgentry))
                        / sizeof(struct sgentry);
        dev->comm_interface = AAC_COMM_PRODUCER;
-       dev->raw_io_64 = 0;
+       dev->raw_io_interface = dev->raw_io_64 = 0;
+
        if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES,
                0, 0, 0, 0, 0, 0, status+0, status+1, status+2, NULL, NULL)) &&
                        (status[0] == 0x00000001)) {
                if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64))
                        dev->raw_io_64 = 1;
-               if (dev->a_ops.adapter_comm &&
-                   (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM)))
-                       dev->comm_interface = AAC_COMM_MESSAGE;
+               if (dev->a_ops.adapter_comm) {
+                       if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE1)) {
+                               dev->comm_interface = AAC_COMM_MESSAGE_TYPE1;
+                               dev->raw_io_interface = 1;
+                       } else if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM)) {
+                               dev->comm_interface = AAC_COMM_MESSAGE;
+                               dev->raw_io_interface = 1;
+                       }
+               }
                if ((dev->comm_interface == AAC_COMM_MESSAGE) &&
                    (status[2] > dev->base_size)) {
                        aac_adapter_ioremap(dev, 0);
@@ -350,10 +380,12 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
                 *      status[3] & 0xFFFF      maximum number FIBs outstanding
                 */
                host->max_sectors = (status[1] >> 16) << 1;
-               dev->max_fib_size = status[1] & 0xFFFF;
+               /* Multiple of 32 for PMC */
+               dev->max_fib_size = status[1] & 0xFFE0;
                host->sg_tablesize = status[2] >> 16;
                dev->sg_tablesize = status[2] & 0xFFFF;
                host->can_queue = (status[3] & 0xFFFF) - AAC_NUM_MGT_FIB;
+               dev->max_num_aif = status[4] & 0xFFFF;
                /*
                 *      NOTE:
                 *      All these overrides are based on a fixed internal
index 060ac4bd5a14ecbde8553bba88019512314ec6c4..dd7ad3ba2dadc57154f1ea44ef8efff2dd80b3c2 100644 (file)
@@ -5,7 +5,8 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2010 Adaptec, Inc.
+ *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -63,9 +64,11 @@ static int fib_map_alloc(struct aac_dev *dev)
          "allocate hardware fibs pci_alloc_consistent(%p, %d * (%d + %d), %p)\n",
          dev->pdev, dev->max_fib_size, dev->scsi_host_ptr->can_queue,
          AAC_NUM_MGT_FIB, &dev->hw_fib_pa));
-       if((dev->hw_fib_va = pci_alloc_consistent(dev->pdev, dev->max_fib_size
-         * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB),
-         &dev->hw_fib_pa))==NULL)
+       dev->hw_fib_va = pci_alloc_consistent(dev->pdev,
+               (dev->max_fib_size + sizeof(struct aac_fib_xporthdr))
+               * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) + (ALIGN32 - 1),
+               &dev->hw_fib_pa);
+       if (dev->hw_fib_va == NULL)
                return -ENOMEM;
        return 0;
 }
@@ -110,9 +113,22 @@ int aac_fib_setup(struct aac_dev * dev)
        if (i<0)
                return -ENOMEM;
 
+       /* 32 byte alignment for PMC */
+       hw_fib_pa = (dev->hw_fib_pa + (ALIGN32 - 1)) & ~(ALIGN32 - 1);
+       dev->hw_fib_va = (struct hw_fib *)((unsigned char *)dev->hw_fib_va +
+               (hw_fib_pa - dev->hw_fib_pa));
+       dev->hw_fib_pa = hw_fib_pa;
+       memset(dev->hw_fib_va, 0,
+               (dev->max_fib_size + sizeof(struct aac_fib_xporthdr)) *
+               (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB));
+
+       /* add Xport header */
+       dev->hw_fib_va = (struct hw_fib *)((unsigned char *)dev->hw_fib_va +
+               sizeof(struct aac_fib_xporthdr));
+       dev->hw_fib_pa += sizeof(struct aac_fib_xporthdr);
+
        hw_fib = dev->hw_fib_va;
        hw_fib_pa = dev->hw_fib_pa;
-       memset(hw_fib, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB));
        /*
         *      Initialise the fibs
         */
@@ -129,8 +145,10 @@ int aac_fib_setup(struct aac_dev * dev)
                hw_fib->header.XferState = cpu_to_le32(0xffffffff);
                hw_fib->header.SenderSize = cpu_to_le16(dev->max_fib_size);
                fibptr->hw_fib_pa = hw_fib_pa;
-               hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + dev->max_fib_size);
-               hw_fib_pa = hw_fib_pa + dev->max_fib_size;
+               hw_fib = (struct hw_fib *)((unsigned char *)hw_fib +
+                       dev->max_fib_size + sizeof(struct aac_fib_xporthdr));
+               hw_fib_pa = hw_fib_pa +
+                       dev->max_fib_size + sizeof(struct aac_fib_xporthdr);
        }
        /*
         *      Add the fib chain to the free list
@@ -664,9 +682,14 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
        unsigned long nointr = 0;
        unsigned long qflags;
 
+       if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) {
+               kfree(hw_fib);
+               return 0;
+       }
+
        if (hw_fib->header.XferState == 0) {
                if (dev->comm_interface == AAC_COMM_MESSAGE)
-                       kfree (hw_fib);
+                       kfree(hw_fib);
                return 0;
        }
        /*
@@ -674,7 +697,7 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
         */
        if (hw_fib->header.StructType != FIB_MAGIC) {
                if (dev->comm_interface == AAC_COMM_MESSAGE)
-                       kfree (hw_fib);
+                       kfree(hw_fib);
                return -EINVAL;
        }
        /*
index 9c7408fe8c7d1cb2d630e40e245cc9e642912441..f0c66a80ad13ef12cd183d46c28b5c3bd8cb7b8b 100644 (file)
@@ -5,7 +5,8 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2010 Adaptec, Inc.
+ *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -228,6 +229,48 @@ unsigned int aac_command_normal(struct aac_queue *q)
        return 0;
 }
 
+/*
+ *
+ * aac_aif_callback
+ * @context: the context set in the fib - here it is scsi cmd
+ * @fibptr: pointer to the fib
+ *
+ * Handles the AIFs - new method (SRC)
+ *
+ */
+
+static void aac_aif_callback(void *context, struct fib * fibptr)
+{
+       struct fib *fibctx;
+       struct aac_dev *dev;
+       struct aac_aifcmd *cmd;
+       int status;
+
+       fibctx = (struct fib *)context;
+       BUG_ON(fibptr == NULL);
+       dev = fibptr->dev;
+
+       if (fibptr->hw_fib_va->header.XferState &
+           cpu_to_le32(NoMoreAifDataAvailable)) {
+               aac_fib_complete(fibptr);
+               aac_fib_free(fibptr);
+               return;
+       }
+
+       aac_intr_normal(dev, 0, 1, 0, fibptr->hw_fib_va);
+
+       aac_fib_init(fibctx);
+       cmd = (struct aac_aifcmd *) fib_data(fibctx);
+       cmd->command = cpu_to_le32(AifReqEvent);
+
+       status = aac_fib_send(AifRequest,
+               fibctx,
+               sizeof(struct hw_fib)-sizeof(struct aac_fibhdr),
+               FsaNormal,
+               0, 1,
+               (fib_callback)aac_aif_callback, fibctx);
+}
+
 
 /**
  *     aac_intr_normal -       Handle command replies
@@ -238,19 +281,17 @@ unsigned int aac_command_normal(struct aac_queue *q)
  *     know there is a response on our normal priority queue. We will pull off
  *     all QE there are and wake up all the waiters before exiting.
  */
-
-unsigned int aac_intr_normal(struct aac_dev * dev, u32 index)
+unsigned int aac_intr_normal(struct aac_dev *dev, u32 index,
+                       int isAif, int isFastResponse, struct hw_fib *aif_fib)
 {
        unsigned long mflags;
        dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index));
-       if ((index & 0x00000002L)) {
+       if (isAif == 1) {       /* AIF - common */
                struct hw_fib * hw_fib;
                struct fib * fib;
                struct aac_queue *q = &dev->queues->queue[HostNormCmdQueue];
                unsigned long flags;
 
-               if (index == 0xFFFFFFFEL) /* Special Case */
-                       return 0;         /* Do nothing */
                /*
                 *      Allocate a FIB. For non queued stuff we can just use
                 * the stack so we are happy. We need a fib object in order to
@@ -263,8 +304,13 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 index)
                        kfree (fib);
                        return 1;
                }
-               memcpy(hw_fib, (struct hw_fib *)(((uintptr_t)(dev->regs.sa)) +
-                 (index & ~0x00000002L)), sizeof(struct hw_fib));
+               if (aif_fib != NULL) {
+                       memcpy(hw_fib, aif_fib, sizeof(struct hw_fib));
+               } else {
+                       memcpy(hw_fib,
+                               (struct hw_fib *)(((uintptr_t)(dev->regs.sa)) +
+                               index), sizeof(struct hw_fib));
+               }
                INIT_LIST_HEAD(&fib->fiblink);
                fib->type = FSAFS_NTC_FIB_CONTEXT;
                fib->size = sizeof(struct fib);
@@ -277,9 +323,26 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 index)
                wake_up_interruptible(&q->cmdready);
                spin_unlock_irqrestore(q->lock, flags);
                return 1;
+       } else if (isAif == 2) {        /* AIF - new (SRC) */
+               struct fib *fibctx;
+               struct aac_aifcmd *cmd;
+
+               fibctx = aac_fib_alloc(dev);
+               if (!fibctx)
+                       return 1;
+               aac_fib_init(fibctx);
+
+               cmd = (struct aac_aifcmd *) fib_data(fibctx);
+               cmd->command = cpu_to_le32(AifReqEvent);
+
+               return aac_fib_send(AifRequest,
+                       fibctx,
+                       sizeof(struct hw_fib)-sizeof(struct aac_fibhdr),
+                       FsaNormal,
+                       0, 1,
+                       (fib_callback)aac_aif_callback, fibctx);
        } else {
-               int fast = index & 0x01;
-               struct fib * fib = &dev->fibs[index >> 2];
+               struct fib *fib = &dev->fibs[index];
                struct hw_fib * hwfib = fib->hw_fib_va;
 
                /*
@@ -298,7 +361,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 index)
                        return 0;
                }
 
-               if (fast) {
+               if (isFastResponse) {
                        /*
                         *      Doctor the fib
                         */
index 2c93d9496d62dae64b4c2aaf0b78e60edc61ba17..4ff26521d75fe7982797b995319438a7eacd297f 100644 (file)
@@ -5,7 +5,8 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2010 Adaptec, Inc.
+ *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -54,7 +55,7 @@
 
 #include "aacraid.h"
 
-#define AAC_DRIVER_VERSION             "1.1-5"
+#define AAC_DRIVER_VERSION             "1.1-7"
 #ifndef AAC_DRIVER_BRANCH
 #define AAC_DRIVER_BRANCH              ""
 #endif
@@ -161,6 +162,7 @@ static const struct pci_device_id aac_pci_tbl[] __devinitdata = {
        { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 59 }, /* Adaptec Catch All */
        { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 60 }, /* Adaptec Rocket Catch All */
        { 0x9005, 0x0288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 61 }, /* Adaptec NEMER/ARK Catch All */
+       { 0x9005, 0x028b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 62 }, /* Adaptec PMC Catch All */
        { 0,}
 };
 MODULE_DEVICE_TABLE(pci, aac_pci_tbl);
@@ -235,7 +237,8 @@ static struct aac_driver_ident aac_drivers[] = {
        { aac_rx_init, "aacraid",  "Legend  ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend Catchall */
        { aac_rx_init, "aacraid",  "ADAPTEC ", "RAID            ", 2 }, /* Adaptec Catch All */
        { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID            ", 2 }, /* Adaptec Rocket Catch All */
-       { aac_nark_init, "aacraid", "ADAPTEC ", "RAID            ", 2 } /* Adaptec NEMER/ARK Catch All */
+       { aac_nark_init, "aacraid", "ADAPTEC ", "RAID           ", 2 }, /* Adaptec NEMER/ARK Catch All */
+       { aac_src_init, "aacraid", "ADAPTEC ", "RAID            ", 2 } /* Adaptec PMC Catch All */
 };
 
 /**
@@ -653,8 +656,10 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
         * This adapter needs a blind reset, only do so for Adapters that
         * support a register, instead of a commanded, reset.
         */
-       if ((aac->supplement_adapter_info.SupportedOptions2 &
-          AAC_OPTION_MU_RESET) &&
+       if (((aac->supplement_adapter_info.SupportedOptions2 &
+         AAC_OPTION_MU_RESET) ||
+         (aac->supplement_adapter_info.SupportedOptions2 &
+         AAC_OPTION_DOORBELL_RESET)) &&
          aac_check_reset &&
          ((aac_check_reset != 1) ||
           !(aac->supplement_adapter_info.SupportedOptions2 &
index c55f7c862f0e0889541af9c1825fef78a3179c05..f397d21a0c06c78cf96be6a2b1f4f58fa8e2cf83 100644 (file)
@@ -4,7 +4,8 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2006-2007 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2010 Adaptec, Inc.
+ *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index 16d8db5500274f1e4319d612102ac06a2d78edbd..be44de92429a9325d7c04bf98019083bab5ecc78 100644 (file)
@@ -5,7 +5,8 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2010 Adaptec, Inc.
+ *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index 84d77fd86e5bf6d1ff4a18b60066cf1965e0aa70..ce530f113fdb92f18e9889c07de889515a824e61 100644 (file)
@@ -5,7 +5,8 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2010 Adaptec, Inc.
+ *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -84,15 +85,35 @@ static irqreturn_t aac_rx_intr_producer(int irq, void *dev_id)
 
 static irqreturn_t aac_rx_intr_message(int irq, void *dev_id)
 {
+       int isAif, isFastResponse, isSpecial;
        struct aac_dev *dev = dev_id;
        u32 Index = rx_readl(dev, MUnit.OutboundQueue);
        if (unlikely(Index == 0xFFFFFFFFL))
                Index = rx_readl(dev, MUnit.OutboundQueue);
        if (likely(Index != 0xFFFFFFFFL)) {
                do {
-                       if (unlikely(aac_intr_normal(dev, Index))) {
-                               rx_writel(dev, MUnit.OutboundQueue, Index);
-                               rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady);
+                       isAif = isFastResponse = isSpecial = 0;
+                       if (Index & 0x00000002L) {
+                               isAif = 1;
+                               if (Index == 0xFFFFFFFEL)
+                                       isSpecial = 1;
+                               Index &= ~0x00000002L;
+                       } else {
+                               if (Index & 0x00000001L)
+                                       isFastResponse = 1;
+                               Index >>= 2;
+                       }
+                       if (!isSpecial) {
+                               if (unlikely(aac_intr_normal(dev,
+                                               Index, isAif,
+                                               isFastResponse, NULL))) {
+                                       rx_writel(dev,
+                                               MUnit.OutboundQueue,
+                                               Index);
+                                       rx_writel(dev,
+                                               MUnit.ODR,
+                                               DoorBellAdapterNormRespReady);
+                               }
                        }
                        Index = rx_readl(dev, MUnit.OutboundQueue);
                } while (Index != 0xFFFFFFFFL);
@@ -631,6 +652,10 @@ int _aac_rx_init(struct aac_dev *dev)
                        name, instance);
                goto error_iounmap;
        }
+       dev->dbg_base = dev->scsi_host_ptr->base;
+       dev->dbg_base_mapped = dev->base;
+       dev->dbg_size = dev->base_size;
+
        aac_adapter_enable_int(dev);
        /*
         *      Tell the adapter that all is configured, and it can
index 622c21c68e65f8be4b36b9169319bdfe66dfacf6..e5d4457121eaa87d4d88e30094b011e7a56c8d48 100644 (file)
@@ -5,7 +5,8 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2010 Adaptec, Inc.
+ *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -391,6 +392,10 @@ int aac_sa_init(struct aac_dev *dev)
                        name, instance);
                goto error_iounmap;
        }
+       dev->dbg_base = dev->scsi_host_ptr->base;
+       dev->dbg_base_mapped = dev->base;
+       dev->dbg_size = dev->base_size;
+
        aac_adapter_enable_int(dev);
 
        /*
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
new file mode 100644 (file)
index 0000000..c204946
--- /dev/null
@@ -0,0 +1,594 @@
+/*
+ *     Adaptec AAC series RAID controller driver
+ *     (c) Copyright 2001 Red Hat Inc.
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000-2010 Adaptec, Inc.
+ *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  src.c
+ *
+ * Abstract: Hardware Device Interface for PMC SRC based controllers
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/completion.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <scsi/scsi_host.h>
+
+#include "aacraid.h"
+
+static irqreturn_t aac_src_intr_message(int irq, void *dev_id)
+{
+       struct aac_dev *dev = dev_id;
+       unsigned long bellbits, bellbits_shifted;
+       int our_interrupt = 0;
+       int isFastResponse;
+       u32 index, handle;
+
+       bellbits = src_readl(dev, MUnit.ODR_R);
+       if (bellbits & PmDoorBellResponseSent) {
+               bellbits = PmDoorBellResponseSent;
+               /* handle async. status */
+               our_interrupt = 1;
+               index = dev->host_rrq_idx;
+               if (dev->host_rrq[index] == 0) {
+                       u32 old_index = index;
+                       /* adjust index */
+                       do {
+                               index++;
+                               if (index == dev->scsi_host_ptr->can_queue +
+                                                       AAC_NUM_MGT_FIB)
+                                       index = 0;
+                               if (dev->host_rrq[index] != 0)
+                                       break;
+                       } while (index != old_index);
+                       dev->host_rrq_idx = index;
+               }
+               for (;;) {
+                       isFastResponse = 0;
+                       /* remove toggle bit (31) */
+                       handle = (dev->host_rrq[index] & 0x7fffffff);
+                       /* check fast response bit (30) */
+                       if (handle & 0x40000000)
+                               isFastResponse = 1;
+                       handle &= 0x0000ffff;
+                       if (handle == 0)
+                               break;
+
+                       aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL);
+
+                       dev->host_rrq[index++] = 0;
+                       if (index == dev->scsi_host_ptr->can_queue +
+                                               AAC_NUM_MGT_FIB)
+                               index = 0;
+                       dev->host_rrq_idx = index;
+               }
+       } else {
+               bellbits_shifted = (bellbits >> SRC_ODR_SHIFT);
+               if (bellbits_shifted & DoorBellAifPending) {
+                       our_interrupt = 1;
+                       /* handle AIF */
+                       aac_intr_normal(dev, 0, 2, 0, NULL);
+               }
+       }
+
+       if (our_interrupt) {
+               src_writel(dev, MUnit.ODR_C, bellbits);
+               return IRQ_HANDLED;
+       }
+       return IRQ_NONE;
+}
+
+/**
+ *     aac_src_disable_interrupt       -       Disable interrupts
+ *     @dev: Adapter
+ */
+
+static void aac_src_disable_interrupt(struct aac_dev *dev)
+{
+       src_writel(dev, MUnit.OIMR, dev->OIMR = 0xffffffff);
+}
+
+/**
+ *     aac_src_enable_interrupt_message        -       Enable interrupts
+ *     @dev: Adapter
+ */
+
+static void aac_src_enable_interrupt_message(struct aac_dev *dev)
+{
+       src_writel(dev, MUnit.OIMR, dev->OIMR = 0xfffffff8);
+}
+
+/**
+ *     src_sync_cmd    -       send a command and wait
+ *     @dev: Adapter
+ *     @command: Command to execute
+ *     @p1: first parameter
+ *     @ret: adapter status
+ *
+ *     This routine will send a synchronous command to the adapter and wait
+ *     for its completion.
+ */
+
+static int src_sync_cmd(struct aac_dev *dev, u32 command,
+       u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6,
+       u32 *status, u32 * r1, u32 * r2, u32 * r3, u32 * r4)
+{
+       unsigned long start;
+       int ok;
+
+       /*
+        *      Write the command into Mailbox 0
+        */
+       writel(command, &dev->IndexRegs->Mailbox[0]);
+       /*
+        *      Write the parameters into Mailboxes 1 - 6
+        */
+       writel(p1, &dev->IndexRegs->Mailbox[1]);
+       writel(p2, &dev->IndexRegs->Mailbox[2]);
+       writel(p3, &dev->IndexRegs->Mailbox[3]);
+       writel(p4, &dev->IndexRegs->Mailbox[4]);
+
+       /*
+        *      Clear the synch command doorbell to start on a clean slate.
+        */
+       src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
+
+       /*
+        *      Disable doorbell interrupts
+        */
+       src_writel(dev, MUnit.OIMR, dev->OIMR = 0xffffffff);
+
+       /*
+        *      Force the completion of the mask register write before issuing
+        *      the interrupt.
+        */
+       src_readl(dev, MUnit.OIMR);
+
+       /*
+        *      Signal that there is a new synch command
+        */
+       src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT);
+
+       ok = 0;
+       start = jiffies;
+
+       /*
+        *      Wait up to 30 seconds
+        */
+       while (time_before(jiffies, start+30*HZ)) {
+               /* Delay 5 microseconds to let Mon960 get info. */
+               udelay(5);
+
+               /* Mon960 will set doorbell0 bit
+                * when it has completed the command
+                */
+               if ((src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT) & OUTBOUNDDOORBELL_0) {
+                       /* Clear the doorbell */
+                       src_writel(dev,
+                               MUnit.ODR_C,
+                               OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
+                       ok = 1;
+                       break;
+               }
+
+                /* Yield the processor in case we are slow */
+               msleep(1);
+       }
+       if (unlikely(ok != 1)) {
+                /* Restore interrupt mask even though we timed out */
+               aac_adapter_enable_int(dev);
+               return -ETIMEDOUT;
+       }
+
+        /* Pull the synch status from Mailbox 0 */
+       if (status)
+               *status = readl(&dev->IndexRegs->Mailbox[0]);
+       if (r1)
+               *r1 = readl(&dev->IndexRegs->Mailbox[1]);
+       if (r2)
+               *r2 = readl(&dev->IndexRegs->Mailbox[2]);
+       if (r3)
+               *r3 = readl(&dev->IndexRegs->Mailbox[3]);
+       if (r4)
+               *r4 = readl(&dev->IndexRegs->Mailbox[4]);
+
+        /* Clear the synch command doorbell */
+       src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
+
+        /* Restore interrupt mask */
+       aac_adapter_enable_int(dev);
+       return 0;
+
+}
+
+/**
+ *     aac_src_interrupt_adapter       -       interrupt adapter
+ *     @dev: Adapter
+ *
+ *     Send an interrupt to the i960 and breakpoint it.
+ */
+
+static void aac_src_interrupt_adapter(struct aac_dev *dev)
+{
+       src_sync_cmd(dev, BREAKPOINT_REQUEST,
+               0, 0, 0, 0, 0, 0,
+               NULL, NULL, NULL, NULL, NULL);
+}
+
+/**
+ *     aac_src_notify_adapter          -       send an event to the adapter
+ *     @dev: Adapter
+ *     @event: Event to send
+ *
+ *     Notify the i960 that something it probably cares about has
+ *     happened.
+ */
+
+static void aac_src_notify_adapter(struct aac_dev *dev, u32 event)
+{
+       switch (event) {
+
+       case AdapNormCmdQue:
+               src_writel(dev, MUnit.ODR_C,
+                       INBOUNDDOORBELL_1 << SRC_ODR_SHIFT);
+               break;
+       case HostNormRespNotFull:
+               src_writel(dev, MUnit.ODR_C,
+                       INBOUNDDOORBELL_4 << SRC_ODR_SHIFT);
+               break;
+       case AdapNormRespQue:
+               src_writel(dev, MUnit.ODR_C,
+                       INBOUNDDOORBELL_2 << SRC_ODR_SHIFT);
+               break;
+       case HostNormCmdNotFull:
+               src_writel(dev, MUnit.ODR_C,
+                       INBOUNDDOORBELL_3 << SRC_ODR_SHIFT);
+               break;
+       case FastIo:
+               src_writel(dev, MUnit.ODR_C,
+                       INBOUNDDOORBELL_6 << SRC_ODR_SHIFT);
+               break;
+       case AdapPrintfDone:
+               src_writel(dev, MUnit.ODR_C,
+                       INBOUNDDOORBELL_5 << SRC_ODR_SHIFT);
+               break;
+       default:
+               BUG();
+               break;
+       }
+}
+
+/**
+ *     aac_src_start_adapter           -       activate adapter
+ *     @dev:   Adapter
+ *
+ *     Start up processing on an i960 based AAC adapter
+ */
+
+static void aac_src_start_adapter(struct aac_dev *dev)
+{
+       struct aac_init *init;
+
+       init = dev->init;
+       init->HostElapsedSeconds = cpu_to_le32(get_seconds());
+
+       /* We can only use a 32 bit address here */
+       src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa,
+         0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);
+}
+
+/**
+ *     aac_src_check_health
+ *     @dev: device to check if healthy
+ *
+ *     Will attempt to determine if the specified adapter is alive and
+ *     capable of handling requests, returning 0 if alive.
+ */
+static int aac_src_check_health(struct aac_dev *dev)
+{
+       u32 status = src_readl(dev, MUnit.OMR);
+
+       /*
+        *      Check to see if the board failed any self tests.
+        */
+       if (unlikely(status & SELF_TEST_FAILED))
+               return -1;
+
+       /*
+        *      Check to see if the board panic'd.
+        */
+       if (unlikely(status & KERNEL_PANIC))
+               return (status >> 16) & 0xFF;
+       /*
+        *      Wait for the adapter to be up and running.
+        */
+       if (unlikely(!(status & KERNEL_UP_AND_RUNNING)))
+               return -3;
+       /*
+        *      Everything is OK
+        */
+       return 0;
+}
+
+/**
+ *     aac_src_deliver_message
+ *     @fib: fib to issue
+ *
+ *     Will send a fib, returning 0 if successful.
+ */
+static int aac_src_deliver_message(struct fib *fib)
+{
+       struct aac_dev *dev = fib->dev;
+       struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue];
+       unsigned long qflags;
+       u32 fibsize;
+       u64 address;
+       struct aac_fib_xporthdr *pFibX;
+
+       spin_lock_irqsave(q->lock, qflags);
+       q->numpending++;
+       spin_unlock_irqrestore(q->lock, qflags);
+
+       /* Calculate the amount to the fibsize bits */
+       fibsize = (sizeof(struct aac_fib_xporthdr) +
+               fib->hw_fib_va->header.Size + 127) / 128 - 1;
+       if (fibsize > (ALIGN32 - 1))
+               fibsize = ALIGN32 - 1;
+
+    /* Fill XPORT header */
+       pFibX = (struct aac_fib_xporthdr *)
+               ((unsigned char *)fib->hw_fib_va -
+               sizeof(struct aac_fib_xporthdr));
+       pFibX->Handle = fib->hw_fib_va->header.SenderData + 1;
+       pFibX->HostAddress = fib->hw_fib_pa;
+       pFibX->Size = fib->hw_fib_va->header.Size;
+       address = fib->hw_fib_pa - (u64)sizeof(struct aac_fib_xporthdr);
+
+       src_writel(dev, MUnit.IQ_H, (u32)(address >> 32));
+       src_writel(dev, MUnit.IQ_L, (u32)(address & 0xffffffff) + fibsize);
+       return 0;
+}
+
+/**
+ *     aac_src_ioremap
+ *     @size: mapping resize request
+ *
+ */
+static int aac_src_ioremap(struct aac_dev *dev, u32 size)
+{
+       if (!size) {
+               iounmap(dev->regs.src.bar0);
+               dev->regs.src.bar0 = NULL;
+               iounmap(dev->base);
+               dev->base = NULL;
+               return 0;
+       }
+       dev->regs.src.bar1 = ioremap(pci_resource_start(dev->pdev, 2),
+               AAC_MIN_SRC_BAR1_SIZE);
+       dev->base = NULL;
+       if (dev->regs.src.bar1 == NULL)
+               return -1;
+       dev->base = dev->regs.src.bar0 = ioremap(dev->scsi_host_ptr->base,
+                               size);
+       if (dev->base == NULL) {
+               iounmap(dev->regs.src.bar1);
+               dev->regs.src.bar1 = NULL;
+               return -1;
+       }
+       dev->IndexRegs = &((struct src_registers __iomem *)
+               dev->base)->IndexRegs;
+       return 0;
+}
+
+static int aac_src_restart_adapter(struct aac_dev *dev, int bled)
+{
+       u32 var, reset_mask;
+
+       if (bled >= 0) {
+               if (bled)
+                       printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
+                               dev->name, dev->id, bled);
+               bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
+                       0, 0, 0, 0, 0, 0, &var, &reset_mask, NULL, NULL, NULL);
+                       if (bled || (var != 0x00000001))
+                               bled = -EINVAL;
+               if (dev->supplement_adapter_info.SupportedOptions2 &
+                       AAC_OPTION_DOORBELL_RESET) {
+                       src_writel(dev, MUnit.IDR, reset_mask);
+                       msleep(5000); /* Delay 5 seconds */
+               }
+       }
+
+       if (src_readl(dev, MUnit.OMR) & KERNEL_PANIC)
+               return -ENODEV;
+
+       if (startup_timeout < 300)
+               startup_timeout = 300;
+
+       return 0;
+}
+
+/**
+ *     aac_src_select_comm     -       Select communications method
+ *     @dev: Adapter
+ *     @comm: communications method
+ */
+int aac_src_select_comm(struct aac_dev *dev, int comm)
+{
+       switch (comm) {
+       case AAC_COMM_MESSAGE:
+               dev->a_ops.adapter_enable_int = aac_src_enable_interrupt_message;
+               dev->a_ops.adapter_intr = aac_src_intr_message;
+               dev->a_ops.adapter_deliver = aac_src_deliver_message;
+               break;
+       default:
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ *  aac_src_init       -       initialize an Cardinal Frey Bar card
+ *  @dev: device to configure
+ *
+ */
+
+int aac_src_init(struct aac_dev *dev)
+{
+       unsigned long start;
+       unsigned long status;
+       int restart = 0;
+       int instance = dev->id;
+       const char *name = dev->name;
+
+       dev->a_ops.adapter_ioremap = aac_src_ioremap;
+       dev->a_ops.adapter_comm = aac_src_select_comm;
+
+       dev->base_size = AAC_MIN_SRC_BAR0_SIZE;
+       if (aac_adapter_ioremap(dev, dev->base_size)) {
+               printk(KERN_WARNING "%s: unable to map adapter.\n", name);
+               goto error_iounmap;
+       }
+
+       /* Failure to reset here is an option ... */
+       dev->a_ops.adapter_sync_cmd = src_sync_cmd;
+       dev->a_ops.adapter_enable_int = aac_src_disable_interrupt;
+       if ((aac_reset_devices || reset_devices) &&
+               !aac_src_restart_adapter(dev, 0))
+               ++restart;
+       /*
+        *      Check to see if the board panic'd while booting.
+        */
+       status = src_readl(dev, MUnit.OMR);
+       if (status & KERNEL_PANIC) {
+               if (aac_src_restart_adapter(dev, aac_src_check_health(dev)))
+                       goto error_iounmap;
+               ++restart;
+       }
+       /*
+        *      Check to see if the board failed any self tests.
+        */
+       status = src_readl(dev, MUnit.OMR);
+       if (status & SELF_TEST_FAILED) {
+               printk(KERN_ERR "%s%d: adapter self-test failed.\n",
+                       dev->name, instance);
+               goto error_iounmap;
+       }
+       /*
+        *      Check to see if the monitor panic'd while booting.
+        */
+       if (status & MONITOR_PANIC) {
+               printk(KERN_ERR "%s%d: adapter monitor panic.\n",
+                       dev->name, instance);
+               goto error_iounmap;
+       }
+       start = jiffies;
+       /*
+        *      Wait for the adapter to be up and running. Wait up to 3 minutes
+        */
+       while (!((status = src_readl(dev, MUnit.OMR)) &
+               KERNEL_UP_AND_RUNNING)) {
+               if ((restart &&
+                 (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||
+                 time_after(jiffies, start+HZ*startup_timeout)) {
+                       printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n",
+                                       dev->name, instance, status);
+                       goto error_iounmap;
+               }
+               if (!restart &&
+                 ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) ||
+                 time_after(jiffies, start + HZ *
+                 ((startup_timeout > 60)
+                   ? (startup_timeout - 60)
+                   : (startup_timeout / 2))))) {
+                       if (likely(!aac_src_restart_adapter(dev,
+                           aac_src_check_health(dev))))
+                               start = jiffies;
+                       ++restart;
+               }
+               msleep(1);
+       }
+       if (restart && aac_commit)
+               aac_commit = 1;
+       /*
+        *      Fill in the common function dispatch table.
+        */
+       dev->a_ops.adapter_interrupt = aac_src_interrupt_adapter;
+       dev->a_ops.adapter_disable_int = aac_src_disable_interrupt;
+       dev->a_ops.adapter_notify = aac_src_notify_adapter;
+       dev->a_ops.adapter_sync_cmd = src_sync_cmd;
+       dev->a_ops.adapter_check_health = aac_src_check_health;
+       dev->a_ops.adapter_restart = aac_src_restart_adapter;
+
+       /*
+        *      First clear out all interrupts.  Then enable the one's that we
+        *      can handle.
+        */
+       aac_adapter_comm(dev, AAC_COMM_MESSAGE);
+       aac_adapter_disable_int(dev);
+       src_writel(dev, MUnit.ODR_C, 0xffffffff);
+       aac_adapter_enable_int(dev);
+
+       if (aac_init_adapter(dev) == NULL)
+               goto error_iounmap;
+       if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1)
+               goto error_iounmap;
+
+       dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
+
+       if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
+                       IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) {
+
+               if (dev->msi)
+                       pci_disable_msi(dev->pdev);
+
+               printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
+                       name, instance);
+               goto error_iounmap;
+       }
+       dev->dbg_base = pci_resource_start(dev->pdev, 2);
+       dev->dbg_base_mapped = dev->regs.src.bar1;
+       dev->dbg_size = AAC_MIN_SRC_BAR1_SIZE;
+
+       aac_adapter_enable_int(dev);
+       /*
+        *      Tell the adapter that all is configured, and it can
+        * start accepting requests
+        */
+       aac_src_start_adapter(dev);
+
+       return 0;
+
+error_iounmap:
+
+       return -1;
+}