Author: dteske
Date: Wed Apr 30 05:59:31 2014
New Revision: 265130
URL: http://svnweb.freebsd.org/changeset/base/265130

Log:
  Add tested known good version of Areca SATA RAID driver (arcmsr) working
  in stable/4. An MFC of slightly later code than that of r144411 (scottl).
  This is a direct commit to stable/4.
  
  Obtained from:  Erich Chen <erich at areca com tw>

Added:
  stable/4/sys/dev/arcmsr/
  stable/4/sys/dev/arcmsr/arcmsr.c   (contents, props changed)
  stable/4/sys/dev/arcmsr/arcmsr.h   (contents, props changed)
  stable/4/sys/modules/arcmsr/
  stable/4/sys/modules/arcmsr/Makefile   (contents, props changed)

Added: stable/4/sys/dev/arcmsr/arcmsr.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ stable/4/sys/dev/arcmsr/arcmsr.c    Wed Apr 30 05:59:31 2014        
(r265130)
@@ -0,0 +1,2587 @@
+/*
+******************************************************************************************
+**        O.S   : FreeBSD
+**   FILE NAME  : arcmsr.c
+**        BY    : Erich Chen   
+**   Description: SCSI RAID Device Driver for 
+**                ARECA (ARC11XX/ARC12XX) SATA RAID HOST Adapter
+**                ARCMSR RAID Host adapter[RAID controller:INTEL 331(PCI-X) 
341(PCI-EXPRESS) chip set]
+******************************************************************************************
+************************************************************************
+**
+** Copyright (c) 2004-2006 ARECA Co. Ltd.
+**        Erich Chen, Taipei Taiwan All rights reserved.
+**
+** Redistribution and use in source and binary forms,with or without
+** modification,are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice,this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice,this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+**    derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES,INCLUDING,BUT NOT LIMITED TO,THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,INDIRECT,
+** INCIDENTAL,SPECIAL,EXEMPLARY,OR CONSEQUENTIAL DAMAGES(INCLUDING,BUT
+** NOT LIMITED TO,PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA,OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY,WHETHER IN CONTRACT,STRICT LIABILITY,OR TORT
+**(INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE,EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**************************************************************************
+** History
+**
+**        REV#         DATE                NAME                 DESCRIPTION
+**     1.00.00.00    3/31/2004        Erich Chen            First release
+**     1.20.00.02   11/29/2004         Erich Chen        bug fix with 
arcmsr_bus_reset when PHY error
+**     1.20.00.03    4/19/2005         Erich Chen        add SATA 24 Ports 
adapter type support
+**                                                       clean unused function
+**     1.20.00.12    9/12/2005         Erich Chen        bug fix with abort 
command handling,firmware version check
+**                                                       and firmware update 
notify for hardware bug fix
+**                                                       handling if none zero 
high part physical address 
+**                                                       of srb resource 
+******************************************************************************************
+** $FreeBSD$
+*/
+#define ARCMSR_DEBUG            0
+/*
+**********************************
+*/
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <sys/devicestat.h>
+#include <sys/kthread.h>
+#include <sys/module.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/sysctl.h>
+#include <sys/poll.h>
+#include <sys/ioccom.h>
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+#include <isa/rtc.h>
+
+#include <machine/bus.h>
+#include <machine/clock.h>
+#include <machine/resource.h>
+#include <machine/atomic.h>
+#include <sys/conf.h>
+#include <sys/rman.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/cam_debug.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
+/* 
+**************************************************************************
+** Define the OS version specific locks 
+**************************************************************************
+*/
+#if __FreeBSD_version >= 500005
+    #include <sys/selinfo.h>
+       #include <sys/mutex.h>
+    #include <dev/pci/pcivar.h>
+    #include <dev/pci/pcireg.h>
+       #define ARCMSR_LOCK_INIT(l, s)          mtx_init(l, s,NULL, 
MTX_DEF|MTX_RECURSE)
+       #define ARCMSR_LOCK_ACQUIRE(l)          mtx_lock(l)
+       #define ARCMSR_LOCK_RELEASE(l)          mtx_unlock(l)
+       typedef struct mtx                      arcmsr_lock_t;
+#else
+    #include <sys/select.h>
+    #include <pci/pcivar.h>
+    #include <pci/pcireg.h>
+       #define ARCMSR_LOCK_INIT(l, s)          simple_lock_init(l)
+       #define ARCMSR_LOCK_ACQUIRE(l)          simple_lock(l)
+       #define ARCMSR_LOCK_RELEASE(l)          simple_unlock(l)
+       typedef struct simplelock               arcmsr_lock_t;
+#endif
+#include <dev/arcmsr/arcmsr.h>
+/*
+**************************************************************************
+** __FreeBSD_version 502010
+**************************************************************************
+*/
+static struct _SRB * arcmsr_get_freesrb(struct _ACB * pACB);
+static u_int8_t arcmsr_seek_cmd2abort(union ccb * pabortccb);
+static u_int8_t arcmsr_wait_msgint_ready(struct _ACB * pACB);
+static u_int32_t arcmsr_probe(device_t dev);
+static u_int32_t arcmsr_attach(device_t dev);
+static u_int32_t arcmsr_detach(device_t dev);
+static u_int32_t arcmsr_iop_ioctlcmd(struct _ACB * pACB,u_int32_t 
ioctl_cmd,caddr_t arg);
+static void arcmsr_iop_parking(struct _ACB *pACB);
+static void arcmsr_shutdown(device_t dev);
+static void arcmsr_interrupt(void *arg);
+static void arcmsr_polling_srbdone(struct _ACB *pACB,struct _SRB *poll_srb);
+static void arcmsr_free_resource(struct _ACB * pACB);
+static void arcmsr_bus_reset(struct _ACB * pACB);
+static void arcmsr_stop_adapter_bgrb(struct _ACB * pACB);
+static void arcmsr_start_adapter_bgrb(struct _ACB * pACB);
+static void arcmsr_iop_init(struct _ACB * pACB);
+static void arcmsr_flush_adapter_cache(struct _ACB * pACB);
+static void arcmsr_queue_wait2go_srb(struct _ACB * pACB,struct _SRB * pSRB);
+static void arcmsr_post_wait2go_srb(struct _ACB * pACB);
+static void arcmsr_post_Qbuffer(struct _ACB * pACB);
+static void arcmsr_abort_allcmd(struct _ACB * pACB);
+static void arcmsr_srb_complete(struct _SRB * pSRB);
+static void arcmsr_iop_reset(struct _ACB * pACB);
+static void arcmsr_report_sense_info(struct _SRB * pSRB);
+static void arcmsr_build_srb(struct _SRB * pSRB, bus_dma_segment_t * dm_segs, 
u_int32_t nseg);
+static int arcmsr_resume(device_t dev);
+static int arcmsr_suspend(device_t dev);
+/*
+*****************************************************************************************
+** Character device switch table
+**struct cdevsw {
+**     d_open_t                *d_open;
+**     d_close_t               *d_close;
+**     d_read_t                *d_read;
+**     d_write_t               *d_write;
+**     d_ioctl_t               *d_ioctl;
+**     d_poll_t                *d_poll;
+**     d_mmap_t                *d_mmap;
+**     d_strategy_t    *d_strategy;
+**     const char          *d_name;       "" base device name, e.g. 'vn' 
+**     int                      d_maj;
+**     d_dump_t            *d_dump;
+**     d_psize_t           *d_psize;
+**     u_int                d_flags;
+**     int                      d_bmaj;
+**     d_kqfilter_t    *d_kqfilter;   "" additions below are not binary 
compatible with 4.2 and below 
+**};
+******************************************************************************************
+*/
+/*
+**************************************************************************
+** Insert a delay in micro-seconds and milli-seconds.
+** static void MDELAY(u_int32_t ms) { while (ms--) UDELAY(1000); }
+**************************************************************************
+*/
+static void UDELAY(u_int32_t us) { DELAY(us); }
+/*
+**************************************************************************
+** 
+**************************************************************************
+*/
+static bus_dmamap_callback_t arcmsr_map_freesrb;
+static bus_dmamap_callback_t arcmsr_executesrb;
+/*
+**************************************************************************
+** 
+**************************************************************************
+*/
+static d_open_t        arcmsr_open;
+static d_close_t arcmsr_close;
+static d_ioctl_t arcmsr_ioctl;
+
+static device_method_t arcmsr_methods[]={
+       DEVMETHOD(device_probe,         arcmsr_probe),
+       DEVMETHOD(device_attach,        arcmsr_attach),
+       DEVMETHOD(device_detach,        arcmsr_detach),
+    DEVMETHOD(device_shutdown, arcmsr_shutdown),
+    DEVMETHOD(device_suspend,  arcmsr_suspend),
+    DEVMETHOD(device_resume,   arcmsr_resume),
+
+    DEVMETHOD(bus_print_child, bus_generic_print_child),
+    DEVMETHOD(bus_driver_added,        bus_generic_driver_added),
+       { 0,0 }
+};
+
+static driver_t arcmsr_driver={
+       "arcmsr",arcmsr_methods,sizeof(struct _ACB)
+};
+
+static devclass_t arcmsr_devclass;
+DRIVER_MODULE(arcmsr,pci,arcmsr_driver,arcmsr_devclass,0,0);
+#ifndef BUS_DMA_COHERENT               
+    #define    BUS_DMA_COHERENT        0x04    /* hint: map memory in a 
coherent way */
+#endif
+#if __FreeBSD_version >= 501000
+    #ifndef D_NEEDGIANT
+        #define D_NEEDGIANT    0x00400000      /* driver want Giant */
+    #endif
+       #ifndef D_VERSION
+        #define D_VERSION      0x20011966
+    #endif
+       static struct cdevsw arcmsr_cdevsw={
+       #if __FreeBSD_version > 502010
+           .d_version = D_VERSION,
+    #endif
+           .d_flags   = D_NEEDGIANT,
+               .d_open    = arcmsr_open,               /* open     */
+               .d_close   = arcmsr_close,              /* close    */
+               .d_ioctl   = arcmsr_ioctl,              /* ioctl    */
+               .d_name    = "arcmsr",                  /* name     */
+       };
+#else
+       #define ARCMSR_CDEV_MAJOR       180
+
+       static struct cdevsw arcmsr_cdevsw = {
+               arcmsr_open,                    /* open     */
+               arcmsr_close,                   /* close    */
+               noread,                             /* read     */
+               nowrite,                            /* write    */
+               arcmsr_ioctl,                   /* ioctl    */
+               nopoll,                         /* poll     */
+               nommap,                             /* mmap     */
+               nostrategy,                         /* strategy */
+               "arcmsr",                               /* name     */
+               ARCMSR_CDEV_MAJOR,                  /* major    */
+               nodump,                             /* dump     */
+               nopsize,                            /* psize    */
+               0                                       /* flags    */
+       };
+#endif
+
+#if __FreeBSD_version < 500005
+    static int arcmsr_open(dev_t dev, int flags, int fmt, struct proc *proc)
+#else
+    #if __FreeBSD_version < 503000
+        static int arcmsr_open(dev_t dev, int flags, int fmt, struct thread 
*proc)
+    #else
+        static int arcmsr_open(struct cdev *dev, int flags, int fmt, 
d_thread_t *proc)
+    #endif 
+#endif
+{
+       #if __FreeBSD_version < 503000
+           struct _ACB * pACB=dev->si_drv1;
+    #else
+               int     unit = minor(dev);
+               struct _ACB * pACB = devclass_get_softc(arcmsr_devclass, unit); 
  
+    #endif
+
+       if(pACB==NULL)
+       {
+               return ENXIO;
+       }
+       return 0;
+}
+/*
+**************************************************************************
+**************************************************************************
+*/
+#if __FreeBSD_version < 500005
+    static int arcmsr_close(dev_t dev, int flags, int fmt, struct proc *proc)
+#else
+    #if __FreeBSD_version < 503000
+        static int arcmsr_close(dev_t dev, int flags, int fmt, struct thread 
*proc)
+    #else
+        static int arcmsr_close(struct cdev *dev, int flags, int fmt, 
d_thread_t *proc)
+    #endif 
+#endif
+{
+       #if __FreeBSD_version < 503000
+           struct _ACB * pACB=dev->si_drv1;
+    #else
+               int     unit = minor(dev);
+               struct _ACB * pACB = devclass_get_softc(arcmsr_devclass, unit); 
  
+    #endif
+
+       if(pACB==NULL)
+       {
+               return ENXIO;
+       }
+       return 0;
+}
+/*
+**************************************************************************
+**ENOENT
+**ENOIOCTL
+**ENOMEM
+**EINVAL
+**************************************************************************
+*/
+#if __FreeBSD_version < 500005
+    static int arcmsr_ioctl(dev_t dev, u_long ioctl_cmd, caddr_t arg, int 
flags, struct proc *proc)
+#else
+    #if __FreeBSD_version < 503000
+        static int arcmsr_ioctl(dev_t dev, u_long ioctl_cmd, caddr_t arg, int 
flags, struct thread *proc)
+    #else
+        static int arcmsr_ioctl(struct cdev *dev, u_long ioctl_cmd, caddr_t 
arg,int flags, d_thread_t *proc)
+    #endif 
+#endif
+{
+       #if __FreeBSD_version < 503000
+           struct _ACB * pACB=dev->si_drv1;
+    #else
+               int     unit = minor(dev);
+               struct _ACB * pACB = devclass_get_softc(arcmsr_devclass, unit); 
  
+    #endif
+
+       if(pACB==NULL)
+       {
+               return ENXIO;
+       }
+    return(arcmsr_iop_ioctlcmd(pACB,ioctl_cmd,arg));
+}
+/*
+*******************************************************************************
+** Bring the controller to a quiescent state, ready for system suspend.
+*******************************************************************************
+*/
+static int arcmsr_suspend(device_t dev)
+{
+    struct _ACB        *pACB = device_get_softc(dev);
+    u_int32_t intmask_org;
+    int        s;
+
+    s = splbio();
+    /* disable all outbound interrupt */
+    intmask_org=readl(&pACB->pmu->outbound_intmask);
+    
writel(&pACB->pmu->outbound_intmask,(intmask_org|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE));
+    /* flush controller */
+       printf("arcmsr%d: flushing cache...\n",pACB->pci_unit);
+       arcmsr_iop_parking(pACB);
+    splx(s);
+    return(0);
+}
+/*
+*******************************************************************************
+** Bring the controller back to a state ready for operation.
+*******************************************************************************
+*/
+static int arcmsr_resume(device_t dev)
+{
+    struct _ACB        *pACB = device_get_softc(dev);
+
+    arcmsr_iop_init(pACB);
+    return(0);
+}
+/*
+*********************************************************************************
+**  Asynchronous notification handler.
+*********************************************************************************
+*/
+static void arcmsr_async(void *cb_arg, u_int32_t code, struct cam_path *path, 
void *arg)
+{
+       struct _ACB * pACB;
+       u_int8_t target_id,target_lun;
+       struct cam_sim * sim;
+       u_int32_t s;
+   
+       s=splcam();
+       sim=(struct cam_sim *) cb_arg;
+       pACB =(struct _ACB *) cam_sim_softc(sim);
+       switch (code)
+       {
+       case AC_LOST_DEVICE:
+               target_id=xpt_path_target_id(path);
+        target_lun=xpt_path_lun_id(path);
+               if((target_id > ARCMSR_MAX_TARGETID) || (target_lun > 
ARCMSR_MAX_TARGETLUN))
+               {
+                       break;
+               }
+        printf("%s:scsi id%d lun%d device lost 
\n",device_get_name(pACB->pci_dev),target_id,target_lun);
+               break;
+       default:
+               break;
+       }
+       splx(s);
+}
+/*
+************************************************************************
+**
+**
+************************************************************************
+*/
+static void arcmsr_flush_adapter_cache(struct _ACB * pACB)
+{
+       writel(&pACB->pmu->inbound_msgaddr0,ARCMSR_INBOUND_MESG0_FLUSH_CACHE);
+       return;
+}
+/*
+**********************************************************************
+** 
+**  
+**
+**********************************************************************
+*/
+static u_int8_t arcmsr_wait_msgint_ready(struct _ACB * pACB)
+{
+       u_int32_t Index;
+       u_int8_t Retries=0x00;
+       do
+       {
+               for(Index=0; Index < 100; Index++)
+               {
+                       if(readl(&pACB->pmu->outbound_intstatus) & 
ARCMSR_MU_OUTBOUND_MESSAGE0_INT)
+                       {
+                               writel(&pACB->pmu->outbound_intstatus, 
ARCMSR_MU_OUTBOUND_MESSAGE0_INT);/*clear interrupt*/
+                               return 0x00;
+                       }
+                       /* one us delay */
+                       UDELAY(10000);
+               }/*max 1 seconds*/
+       }while(Retries++ < 20);/*max 20 sec*/
+       return 0xff;
+}
+/*
+**********************************************************************
+**
+**  Q back this SRB into ACB ArraySRB
+**
+**********************************************************************
+*/
+static void arcmsr_srb_complete(struct _SRB * pSRB)
+{
+       u_int32_t s;
+       struct _ACB * pACB=pSRB->pACB;
+    union ccb * pccb=pSRB->pccb;
+
+       if((pccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
+       {
+               bus_dmasync_op_t op;
+
+               if((pccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
+               {
+                       op = BUS_DMASYNC_POSTREAD;
+               }
+               else
+               {
+                       op = BUS_DMASYNC_POSTWRITE;
+               }
+               bus_dmamap_sync(pACB->buffer_dmat, pSRB->dmamap, op);
+               bus_dmamap_unload(pACB->buffer_dmat, pSRB->dmamap);
+       }
+    s=splcam();
+       atomic_subtract_int(&pACB->srboutstandingcount,1);
+       pSRB->startdone=ARCMSR_SRB_DONE;
+       pSRB->srb_flags=0;
+       pACB->psrbringQ[pACB->srb_doneindex]=pSRB;
+    pACB->srb_doneindex++;
+    pACB->srb_doneindex %= ARCMSR_MAX_FREESRB_NUM;
+    splx(s);
+    xpt_done(pccb);
+       return;
+}
+/*
+**********************************************************************
+**       if scsi error do auto request sense
+**********************************************************************
+*/
+static void arcmsr_report_sense_info(struct _SRB * pSRB)
+{
+       union ccb * pccb=pSRB->pccb;
+       PSENSE_DATA  psenseBuffer=(PSENSE_DATA)&pccb->csio.sense_data;
+
+    pccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
+       pccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
+    if(psenseBuffer) 
+       {
+               memset(psenseBuffer, 0, sizeof(pccb->csio.sense_data));
+               
memcpy(psenseBuffer,pSRB->arcmsr_cdb.SenseData,get_min(sizeof(struct 
_SENSE_DATA),sizeof(pccb->csio.sense_data)));
+           psenseBuffer->ErrorCode=0x70;
+        psenseBuffer->Valid=1;
+               pccb->ccb_h.status |= CAM_AUTOSNS_VALID;
+    }
+    return;
+}
+/*
+*********************************************************************
+** to insert pSRB into tail of pACB wait exec srbQ 
+*********************************************************************
+*/
+static void arcmsr_queue_wait2go_srb(struct _ACB * pACB,struct _SRB * pSRB)
+{
+    u_int32_t s;
+       u_int32_t i=0;
+
+       s=splcam();
+       while(1)
+       {
+               if(pACB->psrbwait2go[i]==NULL)
+               {
+                       pACB->psrbwait2go[i]=pSRB;
+               atomic_add_int(&pACB->srbwait2gocount,1);
+            splx(s);
+                       return;
+               }
+               i++;
+               i%=ARCMSR_MAX_OUTSTANDING_CMD;
+       }
+       return;
+}
+/*
+*********************************************************************
+** 
+*********************************************************************
+*/
+static void arcmsr_abort_allcmd(struct _ACB * pACB)
+{
+       writel(&pACB->pmu->inbound_msgaddr0,ARCMSR_INBOUND_MESG0_ABORT_CMD);
+       return;
+}
+
+/*
+****************************************************************************
+** Routine Description: Reset 80331 iop.
+**           Arguments: 
+**        Return Value: Nothing.
+****************************************************************************
+*/
+static void arcmsr_iop_reset(struct _ACB * pACB)
+{
+       struct _SRB * pSRB;
+       u_int32_t intmask_org,mask;
+    u_int32_t i=0;
+
+       if(pACB->srboutstandingcount!=0)
+       {
+               printf("arcmsr%d: iop reset srboutstandingcount=%d 
\n",pACB->pci_unit,pACB->srboutstandingcount);
+        /* disable all outbound interrupt */
+               intmask_org=readl(&pACB->pmu->outbound_intmask);
+        
writel(&pACB->pmu->outbound_intmask,intmask_org|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE);
+        /* talk to iop 331 outstanding command aborted*/
+               arcmsr_abort_allcmd(pACB);
+               if(arcmsr_wait_msgint_ready(pACB))
+               {
+            printf("arcmsr%d: iop reset wait 'abort all outstanding command' 
timeout \n",pACB->pci_unit);
+               }
+               /*clear all outbound posted Q*/
+               for(i=0;i<ARCMSR_MAX_OUTSTANDING_CMD;i++)
+               {
+                       readl(&pACB->pmu->outbound_queueport);
+               }
+               for(i=0;i<ARCMSR_MAX_FREESRB_NUM;i++)
+               {
+                       pSRB=pACB->psrb_pool[i];
+                       if(pSRB->startdone==ARCMSR_SRB_START)
+                       {
+                               pSRB->startdone=ARCMSR_SRB_ABORTED;
+                pSRB->pccb->ccb_h.status=CAM_REQ_ABORTED;
+                arcmsr_srb_complete(pSRB);
+                       }
+               }
+               /* enable all outbound interrupt */
+               
mask=~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE|ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE|ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE);
+        writel(&pACB->pmu->outbound_intmask,intmask_org & mask);
+               /* post abort all outstanding command message to RAID 
controller */
+       }
+       i=0;
+       while(pACB->srbwait2gocount > 0)
+       {
+               pSRB=pACB->psrbwait2go[i];
+               if(pSRB!=NULL)
+               {
+                       printf("arcmsr%d:iop reset abort command 
srbwait2gocount=%d \n",pACB->pci_unit,pACB->srbwait2gocount);
+                   pACB->psrbwait2go[i]=NULL;
+            pSRB->startdone=ARCMSR_SRB_ABORTED;
+                       pSRB->pccb->ccb_h.status=CAM_REQ_ABORTED;
+            arcmsr_srb_complete(pSRB);
+                       atomic_subtract_int(&pACB->srbwait2gocount,1);
+               }
+               i++;
+               i%=ARCMSR_MAX_OUTSTANDING_CMD;
+       }
+       atomic_set_int(&pACB->srboutstandingcount,0);
+       return;
+}
+/*
+**********************************************************************
+** 
+** PAGE_SIZE=4096 or 8192,PAGE_SHIFT=12
+**********************************************************************
+*/
+static void arcmsr_build_srb(struct _SRB * pSRB, bus_dma_segment_t *dm_segs, 
u_int32_t nseg)
+{
+    struct _ARCMSR_CDB * pARCMSR_CDB=&pSRB->arcmsr_cdb;
+       u_int8_t * psge=(u_int8_t *)&pARCMSR_CDB->u;
+       u_int32_t address_lo,address_hi;
+       union ccb * pccb=pSRB->pccb;
+       struct ccb_scsiio * pcsio=&pccb->csio;
+       u_int32_t arccdbsize=0x30;
+
+       memset(pARCMSR_CDB,0,sizeof(struct _ARCMSR_CDB));
+    pARCMSR_CDB->Bus=0;
+    pARCMSR_CDB->TargetID=pccb->ccb_h.target_id;
+    pARCMSR_CDB->LUN=pccb->ccb_h.target_lun;
+    pARCMSR_CDB->Function=1;
+       pARCMSR_CDB->CdbLength=(u_int8_t)pcsio->cdb_len;
+    pARCMSR_CDB->Context=(unsigned long)pARCMSR_CDB;
+       bcopy(pcsio->cdb_io.cdb_bytes, pARCMSR_CDB->Cdb, pcsio->cdb_len);
+       if(nseg != 0) 
+       {
+               struct _ACB * pACB=pSRB->pACB;
+               bus_dmasync_op_t op;    
+               u_int32_t length,i,cdb_sgcount=0;
+
+               /* map stor port SG list to our iop SG List.*/
+               for(i=0;i<nseg;i++) 
+               {
+                       /* Get the physical address of the current data pointer 
*/
+                       length=(u_int32_t) dm_segs[i].ds_len;
+            address_lo=dma_addr_lo32(dm_segs[i].ds_addr);
+                       address_hi=dma_addr_hi32(dm_segs[i].ds_addr);
+                       if(address_hi==0)
+                       {
+                               struct _SG32ENTRY * pdma_sg=(struct _SG32ENTRY 
*)psge;
+                               pdma_sg->address=address_lo;
+                               pdma_sg->length=length;
+                               psge += sizeof(struct _SG32ENTRY);
+                               arccdbsize += sizeof(struct _SG32ENTRY);
+                       }
+                       else
+                       {
+                               u_int32_t sg64s_size=0,tmplength=length;
+
+                       #if ARCMSR_DEBUG
+                               printf("arcmsr%d: !!!!!!!!!!! address_hi=%x 
\n",pACB->pci_unit,address_hi);
+                               #endif
+                               while(1)
+                               {
+                                       u_int64_t span4G,length0;
+                                       struct _SG64ENTRY * pdma_sg=(struct 
_SG64ENTRY *)psge;
+
+                                       span4G=(u_int64_t)address_lo + 
tmplength;
+                                       pdma_sg->addresshigh=address_hi;
+                                       pdma_sg->address=address_lo;
+                                       if(span4G > 0x100000000)
+                                       {   
+                                               /*see if cross 4G boundary*/
+                                               length0=0x100000000-address_lo;
+                                               
pdma_sg->length=(u_int32_t)length0|IS_SG64_ADDR;
+                                               address_hi=address_hi+1;
+                                               address_lo=0;
+                                               
tmplength=tmplength-(u_int32_t)length0;
+                                               sg64s_size += sizeof(struct 
_SG64ENTRY);
+                                               psge += sizeof(struct 
_SG64ENTRY);
+                                               cdb_sgcount++;
+                                       }
+                                       else
+                                       {
+                                       pdma_sg->length=tmplength|IS_SG64_ADDR;
+                                               sg64s_size += sizeof(struct 
_SG64ENTRY);
+                                               psge += sizeof(struct 
_SG64ENTRY);
+                                               break;
+                                       }
+                               }
+                               arccdbsize += sg64s_size;
+                       }
+                       cdb_sgcount++;
+               }
+               pARCMSR_CDB->sgcount=(u_int8_t)cdb_sgcount;
+               pARCMSR_CDB->DataLength=pcsio->dxfer_len;
+               if( arccdbsize > 256)
+               {
+                       pARCMSR_CDB->Flags|=ARCMSR_CDB_FLAG_SGL_BSIZE;
+               }
+               if((pccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
+               {
+                       op=BUS_DMASYNC_PREREAD;
+               }
+               else
+               {
+                       op=BUS_DMASYNC_PREWRITE;
+                       pARCMSR_CDB->Flags|=ARCMSR_CDB_FLAG_WRITE;
+                       pSRB->srb_flags|=SRB_FLAG_WRITE;
+               }
+       bus_dmamap_sync(pACB->buffer_dmat, pSRB->dmamap, op);
+       }
+    return;
+}
+/*
+**************************************************************************
+**
+**     arcmsr_post_srb - Send a protocol specific ARC send postcard to a AIOC .
+**     handle: Handle of registered ARC protocol driver
+**     adapter_id: AIOC unique identifier(integer)
+**     pPOSTCARD_SEND: Pointer to ARC send postcard
+**
+**     This routine posts a ARC send postcard to the request post FIFO of a
+**     specific ARC adapter.
+**                             
+**************************************************************************
+*/ 
+static void arcmsr_post_srb(struct _ACB * pACB,struct _SRB * pSRB)
+{
+       u_int32_t cdb_shifted_phyaddr=(u_int32_t) pSRB->cdb_shifted_phyaddr;
+       struct _ARCMSR_CDB * pARCMSR_CDB=(struct _ARCMSR_CDB 
*)&pSRB->arcmsr_cdb;
+
+    atomic_add_int(&pACB->srboutstandingcount,1);
+       pSRB->startdone=ARCMSR_SRB_START;
+       if(pARCMSR_CDB->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
+       {
+           
writel(&pACB->pmu->inbound_queueport,cdb_shifted_phyaddr|ARCMSR_SRBPOST_FLAG_SGL_BSIZE);
+       }
+       else
+       {
+           writel(&pACB->pmu->inbound_queueport,cdb_shifted_phyaddr);
+       }
+       return;
+}
+/*
+**************************************************************************
+**
+**
+**************************************************************************
+*/
+static void arcmsr_post_wait2go_srb(struct _ACB * pACB)
+{
+       u_int32_t s;
+       struct _SRB * pSRB;
+       u_int32_t i=0;
+
+    s=splcam();
+       while((pACB->srbwait2gocount > 0) && (pACB->srboutstandingcount < 
ARCMSR_MAX_OUTSTANDING_CMD))
+       {
+               pSRB=pACB->psrbwait2go[i];
+               if(pSRB!=NULL)
+               {
+                       pACB->psrbwait2go[i]=NULL;
+                       arcmsr_post_srb(pACB,pSRB);
+                       atomic_subtract_int(&pACB->srbwait2gocount,1);
+               }
+               i++;
+               i%=ARCMSR_MAX_OUTSTANDING_CMD;
+       }
+       splx(s);
+       return;
+}
+/*
+**********************************************************************
+**   Function: arcmsr_post_Qbuffer
+**     Output: 
+**********************************************************************
+*/
+static void arcmsr_post_Qbuffer(struct _ACB * pACB)
+{
+    u_int32_t s;
+       u_int8_t * pQbuffer;
+       struct _QBUFFER * pwbuffer=(struct _QBUFFER *)&pACB->pmu->ioctl_wbuffer;
+    u_int8_t * iop_data=(u_int8_t *)pwbuffer->data;
+       u_int32_t allxfer_len=0;
+
+    s=splcam();
+       while((pACB->wqbuf_firstindex!=pACB->wqbuf_lastindex) && 
(allxfer_len<124))
+       {
+               pQbuffer=&pACB->wqbuffer[pACB->wqbuf_firstindex];
+               memcpy(iop_data,pQbuffer,1);
+               pACB->wqbuf_firstindex++;
+               pACB->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; /*if last index 
number set it to 0 */
+               iop_data++;
+               allxfer_len++;
+       }
+       pwbuffer->data_len=allxfer_len;
+       /*
+       ** push inbound doorbell and wait reply at hwinterrupt routine for next 
Qbuffer post
+       */
+       
writel(&pACB->pmu->inbound_doorbell,ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK);
+       splx(s);
+       return;
+}
+/*
+************************************************************************
+************************************************************************
+*/
+static void arcmsr_stop_adapter_bgrb(struct _ACB * pACB)
+{
+       pACB->acb_flags |= ACB_F_MSG_STOP_BGRB;
+       pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
+       writel(&pACB->pmu->inbound_msgaddr0,ARCMSR_INBOUND_MESG0_STOP_BGRB);
+       return;
+}
+/*
+************************************************************************
+************************************************************************
+*/
+static void arcmsr_poll(struct cam_sim * psim)
+{
+       arcmsr_interrupt(cam_sim_softc(psim));
+       return;
+}
+/*
+**********************************************************************
+**   Function:  arcmsr_interrupt
+**     Output:  void
+**   CAM  Status field values   
+**typedef enum {
+**     CAM_REQ_INPROG,            CCB request is in progress   
+**     CAM_REQ_CMP,               CCB request completed without error   
+**     CAM_REQ_ABORTED,           CCB request aborted by the host   
+**     CAM_UA_ABORT,              Unable to abort CCB request   
+**     CAM_REQ_CMP_ERR,           CCB request completed with an error   
+**     CAM_BUSY,                      CAM subsytem is busy   
+**     CAM_REQ_INVALID,           CCB request was invalid   
+**     CAM_PATH_INVALID,          Supplied Path ID is invalid   
+**     CAM_DEV_NOT_THERE,         SCSI Device Not Installed/there   
+**     CAM_UA_TERMIO,             Unable to terminate I/O CCB request   
+**     CAM_SEL_TIMEOUT,           Target Selection Timeout   
+**     CAM_CMD_TIMEOUT,           Command timeout   
+**     CAM_SCSI_STATUS_ERROR,     SCSI error, look at error code in CCB   
+**     CAM_MSG_REJECT_REC,        Message Reject Received   
+**     CAM_SCSI_BUS_RESET,        SCSI Bus Reset Sent/Received   
+**     CAM_UNCOR_PARITY,          Uncorrectable parity error occurred   
+**     CAM_AUTOSENSE_FAIL=0x10,   Autosense: request sense cmd fail   
+**     CAM_NO_HBA,                No HBA Detected error   
+**     CAM_DATA_RUN_ERR,          Data Overrun error   
+**     CAM_UNEXP_BUSFREE,         Unexpected Bus Free   
+**     CAM_SEQUENCE_FAIL,         Target Bus Phase Sequence Failure   
+**     CAM_CCB_LEN_ERR,           CCB length supplied is inadequate   
+**     CAM_PROVIDE_FAIL,          Unable to provide requested capability   
+**     CAM_BDR_SENT,              A SCSI BDR msg was sent to target   
+**     CAM_REQ_TERMIO,            CCB request terminated by the host   
+**     CAM_UNREC_HBA_ERROR,       Unrecoverable Host Bus Adapter Error   
+**     CAM_REQ_TOO_BIG,           The request was too large for this host   
+**     CAM_REQUEUE_REQ,          
+**                              * This request should be requeued to preserve
+**                              * transaction ordering.  This typically occurs
+**                              * when the SIM recognizes an error that should
+**                              * freeze the queue and must place additional
+**                              * requests for the target at the sim level
+**                              * back into the XPT queue.
+**                                
+**     CAM_IDE=0x33,              Initiator Detected Error   
+**     CAM_RESRC_UNAVAIL,         Resource Unavailable   
+**     CAM_UNACKED_EVENT,         Unacknowledged Event by Host   
+**     CAM_MESSAGE_RECV,          Message Received in Host Target Mode   
+**     CAM_INVALID_CDB,           Invalid CDB received in Host Target Mode   
+**     CAM_LUN_INVALID,           Lun supplied is invalid   
+**     CAM_TID_INVALID,           Target ID supplied is invalid   
+**     CAM_FUNC_NOTAVAIL,         The requested function is not available   
+**     CAM_NO_NEXUS,              Nexus is not established   
+**     CAM_IID_INVALID,           The initiator ID is invalid   
+**     CAM_CDB_RECVD,             The SCSI CDB has been received   
+**     CAM_LUN_ALRDY_ENA,         The LUN is already eanbeld for target mode   
+**     CAM_SCSI_BUSY,             SCSI Bus Busy   
+**
+**     CAM_DEV_QFRZN=0x40,        The DEV queue is frozen w/this err   
+**
+**                                Autosense data valid for target   
+**     CAM_AUTOSNS_VALID=0x80,
+**     CAM_RELEASE_SIMQ=0x100,   SIM ready to take more commands   
+**     CAM_SIM_QUEUED  =0x200,   SIM has this command in it's queue   
+**
+**     CAM_STATUS_MASK=0x3F,      Mask bits for just the status #   
+**
+**                                Target Specific Adjunct Status   
+**     CAM_SENT_SENSE=0x40000000          sent sense with status   
+**} cam_status;
+**********************************************************************
+*/
+static void arcmsr_interrupt(void *arg)
+{
+       struct _ACB * pACB=(struct _ACB *)arg;
+       struct _SRB * pSRB;
+       u_int32_t flag_srb,outbound_intstatus,outbound_doorbell;
+
+       /*
+       *********************************************
+       **   check outbound intstatus �˹�L�l�t�����a
+       *********************************************
+       */
+       outbound_intstatus=readl(&pACB->pmu->outbound_intstatus) & 
pACB->outbound_int_enable;
+    writel(&pACB->pmu->outbound_intstatus, outbound_intstatus);/*clear 
interrupt*/
+       if(outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT)
+       {
+               /*
+               *********************************************
+               **  DOORBELL �m��! �O�_���l���nñ��
+               *********************************************
+               */
+               outbound_doorbell=readl(&pACB->pmu->outbound_doorbell);
+               writel(&pACB->pmu->outbound_doorbell,outbound_doorbell);/*clear 
interrupt */
+               if(outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK)
+               {
+                       struct _QBUFFER * prbuffer=(struct _QBUFFER 
*)&pACB->pmu->ioctl_rbuffer;
+                       u_int8_t * iop_data=(u_int8_t *)prbuffer->data;
+                       u_int8_t * pQbuffer;
+                       u_int32_t 
my_empty_len,iop_len,rqbuf_firstindex,rqbuf_lastindex;
+
+            /*check this iop data if overflow my rqbuffer*/
+                       rqbuf_lastindex=pACB->rqbuf_lastindex;
+                       rqbuf_firstindex=pACB->rqbuf_firstindex;
+                       iop_len=prbuffer->data_len;
+            
my_empty_len=(rqbuf_firstindex-rqbuf_lastindex-1)&(ARCMSR_MAX_QBUFFER-1);
+                       if(my_empty_len>=iop_len)
+                       {
+                               while(iop_len > 0)
+                               {
+                                       
pQbuffer=&pACB->rqbuffer[pACB->rqbuf_lastindex];
+                                       memcpy(pQbuffer,iop_data,1);
+                                       pACB->rqbuf_lastindex++;
+                                       pACB->rqbuf_lastindex %= 
ARCMSR_MAX_QBUFFER;/*if last index number set it to 0 */
+                                       iop_data++;
+                                       iop_len--;
+                               }
+                               writel(&pACB->pmu->inbound_doorbell, 
ARCMSR_INBOUND_DRIVER_DATA_READ_OK);/*signature, let IOP331 know data has been 
readed */
+                       }
+                       else
+                       {
+                               pACB->acb_flags|=ACB_F_IOPDATA_OVERFLOW;
+                       }
+               }
+               if(outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK)
+               {
+                       /*
+                       *********************************************
+                       **           �ݬݬO�_�٦��l���n���D�H�X
+                       *********************************************
+                       */
+                       if(pACB->wqbuf_firstindex!=pACB->wqbuf_lastindex)
+                       {
+                               u_int8_t * pQbuffer;
+                               struct _QBUFFER * pwbuffer=(struct _QBUFFER 
*)&pACB->pmu->ioctl_wbuffer;
+                               u_int8_t * iop_data=(u_int8_t *)pwbuffer->data;
+                               u_int32_t allxfer_len=0;
+
+                               
while((pACB->wqbuf_firstindex!=pACB->wqbuf_lastindex) && (allxfer_len<124))
+                               {
+                                       
pQbuffer=&pACB->wqbuffer[pACB->wqbuf_firstindex];
+                                       memcpy(iop_data,pQbuffer,1);
+                                       pACB->wqbuf_firstindex++;
+                                       pACB->wqbuf_firstindex %= 
ARCMSR_MAX_QBUFFER; /*if last index number set it to 0 */
+                                       iop_data++;
+                                       allxfer_len++;
+                               }
+                               pwbuffer->data_len=allxfer_len;
+                               /*
+                               ** push inbound doorbell tell iop driver data 
write ok and wait reply on next hwinterrupt for next Qbuffer post
+                               */
+                               
writel(&pACB->pmu->inbound_doorbell,ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK);
+                       }
+                       else
+                       {
+                               pACB->acb_flags |= ACB_F_IOCTL_WQBUFFER_CLEARED;
+                       }
+               }
+       }
+       if(outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT)
+       {
+               int target,lun;
+               /*
+               
*****************************************************************************
+               **               areca cdb command done
+               
*****************************************************************************
+               */
+               while(1)
+               {
+                       if((flag_srb=readl(&pACB->pmu->outbound_queueport)) == 
0xFFFFFFFF)
+                       {
+                               break;/*chip FIFO no srb for completion 
already*/
+                       }
+                       /* check if command done with no error*/
+                       pSRB=(struct _SRB *)(pACB->vir2phy_offset+(flag_srb << 
5));/*frame must be 32 bytes aligned*/
+                       if((pSRB->pACB!=pACB) || 
(pSRB->startdone!=ARCMSR_SRB_START))
+                       {
+                               if(pSRB->startdone==ARCMSR_SRB_ABORTED)
+                               {
+                                       printf("arcmsr%d: scsi id=%d lun=%d 
srb='%p' isr command abort successfully 
\n",pACB->pci_unit,pSRB->pccb->ccb_h.target_id,pSRB->pccb->ccb_h.target_lun,pSRB);
+                                       
pSRB->pccb->ccb_h.status=CAM_REQ_ABORTED;
+                                       arcmsr_srb_complete(pSRB);
+                                       continue;
+                               }
+                               printf("arcmsr%d: isr get an illegal srb 
command done acb='%p' srb='%p' srbacb='%p' startdone=0x%x 
srboutstandingcount=%d 
\n",pACB->pci_unit,pACB,pSRB,pSRB->pACB,pSRB->startdone,pACB->srboutstandingcount);
+                               continue;
+                       }
+                       target=pSRB->pccb->ccb_h.target_id;
+                   lun=pSRB->pccb->ccb_h.target_lun;
+                       if((flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR)==0)
+                       {
+                               if(pACB->devstate[target][lun]==ARECA_RAID_GONE)
+                               {
+                                       
pACB->devstate[target][lun]=ARECA_RAID_GOOD;
+                               }

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to