From owner-svn-src-all@FreeBSD.ORG Wed Apr 30 05:59:32 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 4978338D; Wed, 30 Apr 2014 05:59:32 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 349B81166; Wed, 30 Apr 2014 05:59:32 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s3U5xW2Y065243; Wed, 30 Apr 2014 05:59:32 GMT (envelope-from dteske@svn.freebsd.org) Received: (from dteske@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s3U5xWxg065241; Wed, 30 Apr 2014 05:59:32 GMT (envelope-from dteske@svn.freebsd.org) Message-Id: <201404300559.s3U5xWxg065241@svn.freebsd.org> From: Devin Teske Date: Wed, 30 Apr 2014 05:59:32 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-other@freebsd.org Subject: svn commit: r265130 - in stable/4/sys: dev/arcmsr modules/arcmsr X-SVN-Group: stable-other MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 30 Apr 2014 05:59:32 -0000 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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +/* +************************************************************************** +** Define the OS version specific locks +************************************************************************** +*/ +#if __FreeBSD_version >= 500005 + #include + #include + #include + #include + #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 + #include + #include + #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 +/* +************************************************************************** +** __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;ipmu->outbound_queueport); + } + for(i=0;ipsrb_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;iaddress=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 檢察有無郵差按門鈴 + ********************************************* + */ + 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 叮噹! 是否有郵件要簽收 + ********************************************* + */ + 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) + { + /* + ********************************************* + ** 看看是否還有郵件要順道寄出 + ********************************************* + */ + 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 ***