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-stable
mailing list