/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *     mpt_add_sge - Place a simple SGE at address pAddr.
+ *     mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
  *     @pAddr: virtual address for SGE
  *     @flagslength: SGE flags and data transfer length
  *     @dma_addr: Physical address
  *     This routine places a MPT request frame back on the MPT adapter's
  *     FreeQ.
  */
-void
-mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
+static void
+mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
 {
-       if (sizeof(dma_addr_t) == sizeof(u64)) {
-               SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+       SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
+       pSge->FlagsLength = cpu_to_le32(flagslength);
+       pSge->Address = cpu_to_le32(dma_addr);
+}
+
+/**
+ *     mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
+ *     @pAddr: virtual address for SGE
+ *     @flagslength: SGE flags and data transfer length
+ *     @dma_addr: Physical address
+ *
+ *     This routine places a MPT request frame back on the MPT adapter's
+ *     FreeQ.
+ **/
+static void
+mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
+{
+       SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+       pSge->Address.Low = cpu_to_le32
+                       (lower_32_bits((unsigned long)(dma_addr)));
+       pSge->Address.High = cpu_to_le32
+                       (upper_32_bits((unsigned long)dma_addr));
+       pSge->FlagsLength = cpu_to_le32
+                       ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
+}
+
+/**
+ *     mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr
+ *     (1078 workaround).
+ *     @pAddr: virtual address for SGE
+ *     @flagslength: SGE flags and data transfer length
+ *     @dma_addr: Physical address
+ *
+ *     This routine places a MPT request frame back on the MPT adapter's
+ *     FreeQ.
+ **/
+static void
+mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
+{
+       SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+       u32 tmp;
+
+       pSge->Address.Low = cpu_to_le32
+                       (lower_32_bits((unsigned long)(dma_addr)));
+       tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
+
+       /*
+        * 1078 errata workaround for the 36GB limitation
+        */
+       if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32)  == 9) {
+               flagslength |=
+                   MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
+               tmp |= (1<<31);
+               if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
+                       printk(KERN_DEBUG "1078 P0M2 addressing for "
+                           "addr = 0x%llx len = %d\n",
+                           (unsigned long long)dma_addr,
+                           MPI_SGE_LENGTH(flagslength));
+       }
+
+       pSge->Address.High = cpu_to_le32(tmp);
+       pSge->FlagsLength = cpu_to_le32(
+               (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
+ *     @pAddr: virtual address for SGE
+ *     @next: nextChainOffset value (u32's)
+ *     @length: length of next SGL segment
+ *     @dma_addr: Physical address
+ *
+ */
+static void
+mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
+{
+               SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
+               pChain->Length = cpu_to_le16(length);
+               pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
+               pChain->NextChainOffset = next;
+               pChain->Address = cpu_to_le32(dma_addr);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
+ *     @pAddr: virtual address for SGE
+ *     @next: nextChainOffset value (u32's)
+ *     @length: length of next SGL segment
+ *     @dma_addr: Physical address
+ *
+ */
+static void
+mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
+{
+               SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
                u32 tmp = dma_addr & 0xFFFFFFFF;
 
-               pSge->FlagsLength = cpu_to_le32(flagslength);
-               pSge->Address.Low = cpu_to_le32(tmp);
-               tmp = (u32) ((u64)dma_addr >> 32);
-               pSge->Address.High = cpu_to_le32(tmp);
+               pChain->Length = cpu_to_le16(length);
+               pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
+                                MPI_SGE_FLAGS_64_BIT_ADDRESSING);
 
-       } else {
-               SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
-               pSge->FlagsLength = cpu_to_le32(flagslength);
-               pSge->Address = cpu_to_le32(dma_addr);
-       }
+               pChain->NextChainOffset = next;
+
+               pChain->Address.Low = cpu_to_le32(tmp);
+               tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
+               pChain->Address.High = cpu_to_le32(tmp);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
        }
        flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
        flags_length |= ioc->HostPageBuffer_sz;
-       mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
+       ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
        ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
 
 return 0;
 
        pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
 
-       if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
-           && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
-               dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
-                   ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
-                   ioc->name));
-       } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
-           && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
-               dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
-                   ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
-                   ioc->name));
+       if (sizeof(dma_addr_t) > 4) {
+               const uint64_t required_mask = dma_get_required_mask
+                   (&pdev->dev);
+               if (required_mask > DMA_BIT_MASK(32)
+                       && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
+                       && !pci_set_consistent_dma_mask(pdev,
+                                                DMA_BIT_MASK(64))) {
+                       ioc->dma_mask = DMA_BIT_MASK(64);
+                       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+                               ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
+                               ioc->name));
+               } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
+                       && !pci_set_consistent_dma_mask(pdev,
+                                               DMA_BIT_MASK(32))) {
+                       ioc->dma_mask = DMA_BIT_MASK(32);
+                       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+                               ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
+                               ioc->name));
+               } else {
+                       printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
+                           ioc->name, pci_name(pdev));
+                       return r;
+               }
        } else {
-               printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
-                   ioc->name, pci_name(pdev));
-               pci_release_selected_regions(pdev, ioc->bars);
-               return r;
+               if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
+                       && !pci_set_consistent_dma_mask(pdev,
+                                               DMA_BIT_MASK(32))) {
+                       ioc->dma_mask = DMA_BIT_MASK(32);
+                       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+                               ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
+                               ioc->name));
+               } else {
+                       printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
+                           ioc->name, pci_name(pdev));
+                       return r;
+               }
        }
 
        mem_phys = msize = 0;
                return r;
        }
 
+       /*
+        * Setting up proper handlers for scatter gather handling
+        */
+       if (ioc->dma_mask == DMA_BIT_MASK(64)) {
+               if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
+                       ioc->add_sge = &mpt_add_sge_64bit_1078;
+               else
+                       ioc->add_sge = &mpt_add_sge_64bit;
+               ioc->add_chain = &mpt_add_chain_64bit;
+               ioc->sg_addr_size = 8;
+       } else {
+               ioc->add_sge = &mpt_add_sge;
+               ioc->add_chain = &mpt_add_chain;
+               ioc->sg_addr_size = 4;
+       }
+       ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
+
        ioc->alloc_total = sizeof(MPT_ADAPTER);
        ioc->req_sz = MPT_DEFAULT_FRAME_SIZE;           /* avoid div by zero! */
        ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
        if (err)
                return err;
 
+       if (ioc->dma_mask == DMA_BIT_MASK(64)) {
+               if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
+                       ioc->add_sge = &mpt_add_sge_64bit_1078;
+               else
+                       ioc->add_sge = &mpt_add_sge_64bit;
+               ioc->add_chain = &mpt_add_chain_64bit;
+               ioc->sg_addr_size = 8;
+       } else {
+
+               ioc->add_sge = &mpt_add_sge;
+               ioc->add_chain = &mpt_add_chain;
+               ioc->sg_addr_size = 4;
+       }
+       ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
+
        printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
            ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
            CHIPREG_READ32(&ioc->chip->Doorbell));
        FWUpload_t              *prequest;
        FWUploadReply_t         *preply;
        FWUploadTCSGE_t         *ptcsge;
-       int                      sgeoffset;
        u32                      flagsLength;
        int                      ii, sz, reply_sz;
        int                      cmdStatus;
-
+       int                     request_size;
        /* If the image size is 0, we are done.
         */
        if ((sz = ioc->facts.FWImageSize) == 0)
        ptcsge->ImageSize = cpu_to_le32(sz);
        ptcsge++;
 
-       sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
-
        flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
-       mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
-
-       sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
-       dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
-           ioc->name, prequest, sgeoffset));
+       ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
+       request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
+           ioc->SGE_size;
+       dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
+           " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
+           ioc->facts.FWImageSize, request_size));
        DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
 
-       ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
-                               reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
+       ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
+           reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
 
        dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
 
         * num_sge = num sge in request frame + last chain buffer
         * scale = num sge per chain buffer if no chain element
         */
-       scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
-       if (sizeof(dma_addr_t) == sizeof(u64))
-               num_sge =  scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
+       scale = ioc->req_sz / ioc->SGE_size;
+       if (ioc->sg_addr_size == sizeof(u64))
+               num_sge =  scale + (ioc->req_sz - 60) / ioc->SGE_size;
        else
-               num_sge =  1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
+               num_sge =  1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
 
-       if (sizeof(dma_addr_t) == sizeof(u64)) {
+       if (ioc->sg_addr_size == sizeof(u64)) {
                numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
-                       (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
+                       (ioc->req_sz - 60) / ioc->SGE_size;
        } else {
-               numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
-                       (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
+               numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
+                   scale + (ioc->req_sz - 64) / ioc->SGE_size;
        }
        dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
                ioc->name, num_sge, numSGE));
        dma_addr_t alloc_dma;
        u8 *mem;
        int i, reply_sz, sz, total_size, num_chain;
+       u64     dma_mask;
+
+       dma_mask = 0;
 
        /*  Prime reply FIFO...  */
 
        if (ioc->reply_frames == NULL) {
                if ( (num_chain = initChainBuffers(ioc)) < 0)
                        return -1;
+               /*
+                * 1078 errata workaround for the 36GB limitation
+                */
+               if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
+                   ioc->dma_mask > DMA_35BIT_MASK) {
+                       if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
+                           && !pci_set_consistent_dma_mask(ioc->pcidev,
+                           DMA_BIT_MASK(32))) {
+                               dma_mask = DMA_35BIT_MASK;
+                               d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                                   "setting 35 bit addressing for "
+                                   "Request/Reply/Chain and Sense Buffers\n",
+                                   ioc->name));
+                       } else {
+                               /*Reseting DMA mask to 64 bit*/
+                               pci_set_dma_mask(ioc->pcidev,
+                                       DMA_BIT_MASK(64));
+                               pci_set_consistent_dma_mask(ioc->pcidev,
+                                       DMA_BIT_MASK(64));
+
+                               printk(MYIOC_s_ERR_FMT
+                                   "failed setting 35 bit addressing for "
+                                   "Request/Reply/Chain and Sense Buffers\n",
+                                   ioc->name);
+                               return -1;
+                       }
+               }
 
                total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
                dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
                alloc_dma += ioc->reply_sz;
        }
 
+       if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
+           ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
+           ioc->dma_mask))
+               d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "restoring 64 bit addressing\n", ioc->name));
+
        return 0;
 
 out_fail:
                                ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
                ioc->sense_buf_pool = NULL;
        }
+
+       if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
+           DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
+           DMA_BIT_MASK(64)))
+               d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "restoring 64 bit addressing\n", ioc->name));
+
        return -1;
 }
 
                        ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
        }
 
-       mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
+       ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
 
        /* Append pCfg pointer to end of mf
         */
 EXPORT_SYMBOL(mpt_put_msg_frame);
 EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
 EXPORT_SYMBOL(mpt_free_msg_frame);
-EXPORT_SYMBOL(mpt_add_sge);
 EXPORT_SYMBOL(mpt_send_handshake_request);
 EXPORT_SYMBOL(mpt_verify_adapter);
 EXPORT_SYMBOL(mpt_GetIocState);
 
 #define COPYRIGHT      "Copyright (c) 1999-2008 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON       "3.04.07"
-#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.04.07"
+#define MPT_LINUX_VERSION_COMMON       "3.04.08"
+#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.04.08"
 #define WHAT_MAGIC_STRING              "@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
 
 #define MPT_COALESCING_TIMEOUT         0x10
 
+
 /*
  * SCSI transfer rate defines.
  */
        u8              flags;
 };
 
+typedef void (*MPT_ADD_SGE)(void *pAddr, u32 flagslength, dma_addr_t dma_addr);
+typedef void (*MPT_ADD_CHAIN)(void *pAddr, u8 next, u16 length,
+               dma_addr_t dma_addr);
+
 /*
  *  Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
  */
        int                      reply_depth;   /* Num Allocated reply frames */
        int                      reply_sz;      /* Reply frame size */
        int                      num_chain;     /* Number of chain buffers */
+       MPT_ADD_SGE              add_sge;       /* Pointer to add_sge
+                                                  function */
+       MPT_ADD_CHAIN            add_chain;     /* Pointer to add_chain
+                                                  function */
                /* Pool of buffers for chaining. ReqToChain
                 * and ChainToChain track index of chain buffers.
                 * ChainBuffer (DMA) virt/phys addresses.
        struct workqueue_struct *fc_rescan_work_q;
        struct scsi_cmnd        **ScsiLookup;
        spinlock_t                scsi_lookup_lock;
-
+       u64                     dma_mask;
        char                     reset_work_q_name[20];
        struct workqueue_struct *reset_work_q;
        struct delayed_work      fault_reset_work;
        spinlock_t               fault_reset_work_lock;
 
+       u8                      sg_addr_size;
+       u8                      SGE_size;
+
 } MPT_ADAPTER;
 
 /*
        dma_addr_t      Address;
 } MptSge_t;
 
-#define mpt_addr_size() \
-       ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SGE_FLAGS_64_BIT_ADDRESSING : \
-               MPI_SGE_FLAGS_32_BIT_ADDRESSING)
 
-#define mpt_msg_flags() \
-       ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \
-               MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32)
+#define mpt_msg_flags(ioc) \
+       (ioc->sg_addr_size == sizeof(u64)) ?            \
+       MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 :             \
+       MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32
+
+#define MPT_SGE_FLAGS_64_BIT_ADDRESSING \
+       (MPI_SGE_FLAGS_64_BIT_ADDRESSING << MPI_SGE_FLAGS_SHIFT)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
 extern void     mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
 extern void     mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
 extern void     mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
-extern void     mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr);
 
 extern int      mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag);
 extern int      mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
 #define MPT_SGE_FLAGS_END_OF_BUFFER            (0x40000000)
 #define MPT_SGE_FLAGS_LOCAL_ADDRESS            (0x08000000)
 #define MPT_SGE_FLAGS_DIRECTION                        (0x04000000)
-#define MPT_SGE_FLAGS_ADDRESSING               (mpt_addr_size() << MPI_SGE_FLAGS_SHIFT)
 #define MPT_SGE_FLAGS_END_OF_LIST              (0x01000000)
 
 #define MPT_SGE_FLAGS_TRANSACTION_ELEMENT      (0x00000000)
         MPT_SGE_FLAGS_END_OF_BUFFER |  \
         MPT_SGE_FLAGS_END_OF_LIST |    \
         MPT_SGE_FLAGS_SIMPLE_ELEMENT | \
-        MPT_SGE_FLAGS_ADDRESSING | \
         MPT_TRANSFER_IOC_TO_HOST)
 #define MPT_SGE_FLAGS_SSIMPLE_WRITE \
        (MPT_SGE_FLAGS_LAST_ELEMENT |   \
         MPT_SGE_FLAGS_END_OF_BUFFER |  \
         MPT_SGE_FLAGS_END_OF_LIST |    \
         MPT_SGE_FLAGS_SIMPLE_ELEMENT | \
-        MPT_SGE_FLAGS_ADDRESSING | \
         MPT_TRANSFER_HOST_TO_IOC)
 
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
         *      96              8
         *      64              4
         */
-       maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t))
-                       / (sizeof(dma_addr_t) + sizeof(u32));
+       maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) -
+                       sizeof(FWDownloadTCSGE_t))
+                       / iocp->SGE_size;
        if (numfrags > maxfrags) {
                ret = -EMLINK;
                goto fwdl_out;
                if (nib == 0 || nib == 3) {
                        ;
                } else if (sgIn->Address) {
-                       mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
+                       iocp->add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
                        n++;
                        if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
                                printk(MYIOC_s_ERR_FMT "%s@%d::_ioctl_fwdl - "
                }
                sgIn++;
                bl++;
-               sgOut += (sizeof(dma_addr_t) + sizeof(u32));
+               sgOut += iocp->SGE_size;
        }
 
        DBG_DUMP_FW_DOWNLOAD(iocp, (u32 *)mf, numfrags);
         *
         */
        sgl = sglbuf;
-       sg_spill = ((ioc->req_sz - sge_offset)/(sizeof(dma_addr_t) + sizeof(u32))) - 1;
+       sg_spill = ((ioc->req_sz - sge_offset)/ioc->SGE_size) - 1;
        while (bytes_allocd < bytes) {
                this_alloc = min(alloc_sz, bytes-bytes_allocd);
                buflist[buflist_ent].len = this_alloc;
                        dma_addr_t dma_addr;
 
                        bytes_allocd += this_alloc;
-                       sgl->FlagsLength = (0x10000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|this_alloc);
-                       dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir);
+                       sgl->FlagsLength = (0x10000000|sgdir|this_alloc);
+                       dma_addr = pci_map_single(ioc->pcidev,
+                               buflist[buflist_ent].kptr, this_alloc, dir);
                        sgl->Address = dma_addr;
 
                        fragcnt++;
         */
        sz = karg.dataSgeOffset * 4;
        if (karg.dataInSize > 0)
-               sz += sizeof(dma_addr_t) + sizeof(u32);
+               sz += ioc->SGE_size;
        if (karg.dataOutSize > 0)
-               sz += sizeof(dma_addr_t) + sizeof(u32);
+               sz += ioc->SGE_size;
 
        if (sz > ioc->req_sz) {
                printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
                        }
 
                        pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
-                       pScsiReq->MsgFlags |= mpt_msg_flags();
+                       pScsiReq->MsgFlags |= mpt_msg_flags(ioc);
 
 
                        /* verify that app has not requested
                        int dataSize;
 
                        pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
-                       pScsiReq->MsgFlags |= mpt_msg_flags();
+                       pScsiReq->MsgFlags |= mpt_msg_flags(ioc);
 
 
                        /* verify that app has not requested
                        if (karg.dataInSize > 0) {
                                flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
                                                MPI_SGE_FLAGS_END_OF_BUFFER |
-                                               MPI_SGE_FLAGS_DIRECTION |
-                                               mpt_addr_size() )
+                                               MPI_SGE_FLAGS_DIRECTION)
                                                << MPI_SGE_FLAGS_SHIFT;
                        } else {
                                flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
                                /* Set up this SGE.
                                 * Copy to MF and to sglbuf
                                 */
-                               mpt_add_sge(psge, flagsLength, dma_addr_out);
-                               psge += (sizeof(u32) + sizeof(dma_addr_t));
+                               ioc->add_sge(psge, flagsLength, dma_addr_out);
+                               psge += ioc->SGE_size;
 
                                /* Copy user data to kernel space.
                                 */
                                /* Set up this SGE
                                 * Copy to MF and to sglbuf
                                 */
-                               mpt_add_sge(psge, flagsLength, dma_addr_in);
+                               ioc->add_sge(psge, flagsLength, dma_addr_in);
                        }
                }
        } else  {
                /* Add a NULL SGE
                 */
-               mpt_add_sge(psge, flagsLength, (dma_addr_t) -1);
+               ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
        }
 
        ioc->ioctl->wait_done = 0;
        pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma);
        if (!pbuf)
                goto out;
-       mpt_add_sge((char *)&IstwiRWRequest->SGL,
+       ioc->add_sge((char *)&IstwiRWRequest->SGL,
            (MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma);
 
        ioc->ioctl->wait_done = 0;
 
 #define MPT_DEBUG_FC                   0x00080000
 #define MPT_DEBUG_SAS                  0x00100000
 #define MPT_DEBUG_SAS_WIDE             0x00200000
+#define MPT_DEBUG_36GB_MEM              0x00400000
 
 /*
  * CONFIG_FUSION_LOGGING - enabled in Kconfig
 #define dsaswideprintk(IOC, CMD)               \
        MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE)
 
+#define d36memprintk(IOC, CMD)         \
+       MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_36GB_MEM)
 
 
 /*
 
         * A slightly different algorithm is required for
         * 64bit SGEs.
         */
-       scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
-       if (sizeof(dma_addr_t) == sizeof(u64)) {
+       scale = ioc->req_sz/ioc->SGE_size;
+       if (ioc->sg_addr_size == sizeof(u64)) {
                numSGE = (scale - 1) *
                  (ioc->facts.MaxChainDepth-1) + scale +
-                 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
-                 sizeof(u32));
+                 (ioc->req_sz - 60) / ioc->SGE_size;
        } else {
                numSGE = 1 + (scale - 1) *
                  (ioc->facts.MaxChainDepth-1) + scale +
-                 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
-                 sizeof(u32));
+                 (ioc->req_sz - 64) / ioc->SGE_size;
        }
 
        if (numSGE < sh->sg_tablesize) {
 
        /* request */
        flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
                       MPI_SGE_FLAGS_END_OF_BUFFER |
-                      MPI_SGE_FLAGS_DIRECTION |
-                      mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT;
+                      MPI_SGE_FLAGS_DIRECTION)
+                      << MPI_SGE_FLAGS_SHIFT;
        flagsLength |= (req->data_len - 4);
 
        dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
                                      req->data_len, PCI_DMA_BIDIRECTIONAL);
        if (!dma_addr_out)
                goto put_mf;
-       mpt_add_sge(psge, flagsLength, dma_addr_out);
+       ioc->add_sge(psge, flagsLength, dma_addr_out);
        psge += (sizeof(u32) + sizeof(dma_addr_t));
 
        /* response */
                                      rsp->data_len, PCI_DMA_BIDIRECTIONAL);
        if (!dma_addr_in)
                goto unmap;
-       mpt_add_sge(psge, flagsLength, dma_addr_in);
+       ioc->add_sge(psge, flagsLength, dma_addr_in);
 
        mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
 
         * A slightly different algorithm is required for
         * 64bit SGEs.
         */
-       scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
-       if (sizeof(dma_addr_t) == sizeof(u64)) {
+       scale = ioc->req_sz/ioc->SGE_size;
+       if (ioc->sg_addr_size == sizeof(u64)) {
                numSGE = (scale - 1) *
                  (ioc->facts.MaxChainDepth-1) + scale +
-                 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
-                 sizeof(u32));
+                 (ioc->req_sz - 60) / ioc->SGE_size;
        } else {
                numSGE = 1 + (scale - 1) *
                  (ioc->facts.MaxChainDepth-1) + scale +
-                 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
-                 sizeof(u32));
+                 (ioc->req_sz - 64) / ioc->SGE_size;
        }
 
        if (numSGE < sh->sg_tablesize) {
 
 
 #define SNS_LEN(scp)   SCSI_SENSE_BUFFERSIZE
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     mptscsih_add_sge - Place a simple SGE at address pAddr.
- *     @pAddr: virtual address for SGE
- *     @flagslength: SGE flags and data transfer length
- *     @dma_addr: Physical address
- *
- *     This routine places a MPT request frame back on the MPT adapter's
- *     FreeQ.
- */
-static inline void
-mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
-{
-       if (sizeof(dma_addr_t) == sizeof(u64)) {
-               SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
-               u32 tmp = dma_addr & 0xFFFFFFFF;
-
-               pSge->FlagsLength = cpu_to_le32(flagslength);
-               pSge->Address.Low = cpu_to_le32(tmp);
-               tmp = (u32) ((u64)dma_addr >> 32);
-               pSge->Address.High = cpu_to_le32(tmp);
-
-       } else {
-               SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
-               pSge->FlagsLength = cpu_to_le32(flagslength);
-               pSge->Address = cpu_to_le32(dma_addr);
-       }
-} /* mptscsih_add_sge() */
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- *     mptscsih_add_chain - Place a chain SGE at address pAddr.
- *     @pAddr: virtual address for SGE
- *     @next: nextChainOffset value (u32's)
- *     @length: length of next SGL segment
- *     @dma_addr: Physical address
- *
- *     This routine places a MPT request frame back on the MPT adapter's
- *     FreeQ.
- */
-static inline void
-mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
-{
-       if (sizeof(dma_addr_t) == sizeof(u64)) {
-               SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
-               u32 tmp = dma_addr & 0xFFFFFFFF;
-
-               pChain->Length = cpu_to_le16(length);
-               pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
-
-               pChain->NextChainOffset = next;
-
-               pChain->Address.Low = cpu_to_le32(tmp);
-               tmp = (u32) ((u64)dma_addr >> 32);
-               pChain->Address.High = cpu_to_le32(tmp);
-       } else {
-               SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
-               pChain->Length = cpu_to_le16(length);
-               pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
-               pChain->NextChainOffset = next;
-               pChain->Address = cpu_to_le32(dma_addr);
-       }
-} /* mptscsih_add_chain() */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
         */
 
 nextSGEset:
-       numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
+       numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size);
        numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
 
-       sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
+       sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;
 
        /* Get first (num - 1) SG elements
         * Skip any SG entries with a length of 0
                }
 
                v2 = sg_dma_address(sg);
-               mptscsih_add_sge(psge, sgflags | thisxfer, v2);
+               ioc->add_sge(psge, sgflags | thisxfer, v2);
 
                sg = sg_next(sg);       /* Get next SG element from the OS */
-               psge += (sizeof(u32) + sizeof(dma_addr_t));
-               sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+               psge += ioc->SGE_size;
+               sgeOffset += ioc->SGE_size;
                sg_done++;
        }
 
                thisxfer = sg_dma_len(sg);
 
                v2 = sg_dma_address(sg);
-               mptscsih_add_sge(psge, sgflags | thisxfer, v2);
-               /*
-               sg = sg_next(sg);
-               psge += (sizeof(u32) + sizeof(dma_addr_t));
-               */
-               sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+               ioc->add_sge(psge, sgflags | thisxfer, v2);
+               sgeOffset += ioc->SGE_size;
                sg_done++;
 
                if (chainSge) {
                         * Update the chain element
                         * Offset and Length fields.
                         */
-                       mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
+                       ioc->add_chain((char *)chainSge, 0, sgeOffset,
+                               ioc->ChainBufferDMA + chain_dma_off);
                } else {
                        /* The current buffer is the original MF
                         * and there is no Chain buffer.
                 * set properly).
                 */
                if (sg_done) {
-                       u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
+                       u32 *ptmp = (u32 *) (psge - ioc->SGE_size);
                        sgflags = le32_to_cpu(*ptmp);
                        sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
                        *ptmp = cpu_to_le32(sgflags);
                         * Old chain element is now complete.
                         */
                        u8 nextChain = (u8) (sgeOffset >> 2);
-                       sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
-                       mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
+                       sgeOffset += ioc->SGE_size;
+                       ioc->add_chain((char *)chainSge, nextChain, sgeOffset,
+                                        ioc->ChainBufferDMA + chain_dma_off);
                } else {
                        /* The original MF buffer requires a chain buffer -
                         * set the offset.
        pScsiReq->CDBLength = SCpnt->cmd_len;
        pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
        pScsiReq->Reserved = 0;
-       pScsiReq->MsgFlags = mpt_msg_flags();
+       pScsiReq->MsgFlags = mpt_msg_flags(ioc);
        int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
        pScsiReq->Control = cpu_to_le32(scsictl);
 
         */
        if (datalen == 0) {
                /* Add a NULL SGE */
-               mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
+               ioc->add_sge((char *)&pScsiReq->SGL,
+                       MPT_SGE_FLAGS_SSIMPLE_READ | 0,
                        (dma_addr_t) -1);
        } else {
                /* Add a 32 or 64 bit SGE */
 
        pScsiReq->Reserved = 0;
 
-       pScsiReq->MsgFlags = mpt_msg_flags();
+       pScsiReq->MsgFlags = mpt_msg_flags(ioc);
        /* MsgContext set in mpt_get_msg_fram call  */
 
        int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
                        ioc->name, cmd, io->channel, io->id, io->lun));
 
        if (dir == MPI_SCSIIO_CONTROL_READ) {
-               mpt_add_sge((char *) &pScsiReq->SGL,
+               ioc->add_sge((char *) &pScsiReq->SGL,
                        MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
                        io->data_dma);
        } else {
-               mpt_add_sge((char *) &pScsiReq->SGL,
+               ioc->add_sge((char *) &pScsiReq->SGL,
                        MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
                        io->data_dma);
        }
 
        flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
                (IOCPage4Ptr->Header.PageLength + ii) * 4;
 
-       mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
+       ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
 
        ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
        pReq->Reserved2 = 0;
        pReq->ActionDataWord = 0; /* Reserved for this action */
 
-       mpt_add_sge((char *)&pReq->ActionDataSGE,
+       ioc->add_sge((char *)&pReq->ActionDataSGE,
                MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
 
        ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
         * A slightly different algorithm is required for
         * 64bit SGEs.
         */
-       scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
-       if (sizeof(dma_addr_t) == sizeof(u64)) {
+       scale = ioc->req_sz/ioc->SGE_size;
+       if (ioc->sg_addr_size == sizeof(u64)) {
                numSGE = (scale - 1) *
                  (ioc->facts.MaxChainDepth-1) + scale +
-                 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
-                 sizeof(u32));
+                 (ioc->req_sz - 60) / ioc->SGE_size;
        } else {
                numSGE = 1 + (scale - 1) *
                  (ioc->facts.MaxChainDepth-1) + scale +
-                 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
-                 sizeof(u32));
+                 (ioc->req_sz - 64) / ioc->SGE_size;
        }
 
        if (numSGE < sh->sg_tablesize) {