svn commit: r265130 - in stable/4/sys: dev/arcmsr modules/arcmsr

Devin Teske dteske at FreeBSD.org
Wed Apr 30 05:59:32 UTC 2014


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 ***


More information about the svn-src-all mailing list