1c7e93581d
a concept that is fundamentally broken with PAE.
2626 lines
83 KiB
C
2626 lines
83 KiB
C
/*
|
||
******************************************************************************************
|
||
** O.S : FreeBSD
|
||
** FILE NAME : arcmsr.c
|
||
** BY : Erich Chen
|
||
** Description: SCSI RAID Device Driver for
|
||
** ARECA (ARC1110/1120/1160/1210/1220/1260) 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
|
||
******************************************************************************************
|
||
** $FreeBSD$
|
||
*/
|
||
#define ARCMSR_DEBUG 1
|
||
/*
|
||
**********************************
|
||
*/
|
||
#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_memio.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 VOID arcmsr_interrupt(VOID *arg);
|
||
static LONG arcmsr_probe(device_t dev);
|
||
static LONG arcmsr_attach(device_t dev);
|
||
static LONG arcmsr_detach(device_t dev);
|
||
static VOID arcmsr_shutdown(device_t dev);
|
||
#if 0
|
||
ULONG arcmsr_make_timespec(ULONG year,ULONG mon,ULONG day,ULONG hour,ULONG min,ULONG sec);
|
||
ULONG arcmsr_getcmos_time(VOID);
|
||
#endif
|
||
LONG arcmsr_queue_dpc(PACB pACB,DPCFUN dpcfun,VOID *arg);
|
||
LONG arcmsr_iop_ioctlcmd(PACB pACB,ULONG ioctl_cmd,caddr_t arg);
|
||
BOOLEAN arcmsr_seek_cmd2abort(union ccb * pabortccb);
|
||
BOOLEAN arcmsr_wait_msgint_ready(PACB pACB);
|
||
PSRB arcmsr_get_freesrb(PACB pACB);
|
||
VOID arcmsr_free_resource(PACB pACB);
|
||
VOID arcmsr_bus_reset(PACB pACB);
|
||
VOID arcmsr_stop_adapter_bgrb(PACB pACB);
|
||
VOID arcmsr_start_adapter_bgrb(PACB pACB);
|
||
VOID arcmsr_iop_init(PACB pACB);
|
||
VOID arcmsr_do_dpcQ(PACB pACB);
|
||
VOID arcmsr_flush_adapter_cache(PACB pACB);
|
||
VOID arcmsr_do_thread_works(VOID *arg);
|
||
VOID arcmsr_queue_wait2go_srb(PACB pACB,PSRB pSRB);
|
||
VOID arcmsr_post_wait2go_srb(PACB pACB);
|
||
VOID arcmsr_post_Qbuffer(PACB pACB);
|
||
VOID arcmsr_abort_allcmd(PACB pACB);
|
||
VOID arcmsr_srb_complete(PSRB pSRB);
|
||
VOID arcmsr_iop_reset(PACB pACB);
|
||
VOID arcmsr_report_SenseInfoBuffer(PSRB pSRB);
|
||
VOID arcmsr_build_srb(PSRB pSRB, bus_dma_segment_t *dm_segs, LONG nseg);
|
||
/*
|
||
*****************************************************************************************
|
||
** 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(LONG ms) { while (ms--) UDELAY(1000); }
|
||
**************************************************************************
|
||
*/
|
||
static VOID UDELAY(LONG 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),
|
||
{ 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);
|
||
|
||
#if __FreeBSD_version >= 502010
|
||
static struct cdevsw arcmsr_cdevsw={
|
||
.d_version = D_VERSION,
|
||
.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
|
||
PACB pACB=dev->si_drv1;
|
||
#else
|
||
int unit = minor(dev);
|
||
PACB pACB = devclass_get_softc(arcmsr_devclass, unit);
|
||
#endif
|
||
|
||
if(pACB==NULL)
|
||
{
|
||
return ENXIO;
|
||
}
|
||
/* Check to make sure the device isn't already open */
|
||
if (pACB->acb_flags & ACB_F_IOCTL_OPEN)
|
||
{
|
||
return EBUSY;
|
||
}
|
||
pACB->acb_flags |= ACB_F_IOCTL_OPEN;
|
||
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
|
||
PACB pACB=dev->si_drv1;
|
||
#else
|
||
int unit = minor(dev);
|
||
PACB pACB = devclass_get_softc(arcmsr_devclass, unit);
|
||
#endif
|
||
|
||
if(pACB==NULL)
|
||
{
|
||
return ENXIO;
|
||
}
|
||
pACB->acb_flags &= ~ACB_F_IOCTL_OPEN;
|
||
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
|
||
PACB pACB=dev->si_drv1;
|
||
#else
|
||
int unit = minor(dev);
|
||
PACB pACB = devclass_get_softc(arcmsr_devclass, unit);
|
||
#endif
|
||
|
||
if(pACB==NULL)
|
||
{
|
||
return ENXIO;
|
||
}
|
||
return(arcmsr_iop_ioctlcmd(pACB,ioctl_cmd,arg));
|
||
}
|
||
/*
|
||
**************************************************************************
|
||
**************************************************************************
|
||
*/
|
||
LONG arcmsr_queue_dpc(PACB pACB,DPCFUN dpcfun,VOID *arg)
|
||
{
|
||
ULONG s;
|
||
UCHAR index_pointer;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_queue_dpc................. \n");
|
||
#endif
|
||
|
||
s=splcam();
|
||
index_pointer=(pACB->dpcQ_tail + 1) % ARCMSR_MAX_DPC;
|
||
if(index_pointer==pACB->dpcQ_head)
|
||
{
|
||
splx(s);
|
||
printf("DPC Queue full!\n");
|
||
return -1;
|
||
}
|
||
pACB->dpcQ[pACB->dpcQ_tail].dpcfun=dpcfun;
|
||
pACB->dpcQ[pACB->dpcQ_tail].arg=arg;
|
||
pACB->dpcQ_tail=index_pointer;
|
||
/*
|
||
*********************************************************
|
||
*********************************************************
|
||
*/
|
||
wakeup(pACB->kthread_proc);
|
||
|
||
splx(s);
|
||
return 0;
|
||
}
|
||
/*
|
||
**************************************************************************
|
||
** arcmsr_do_dpcQ
|
||
** execute dpc routine by kernel thread
|
||
***************************************************************************
|
||
*/
|
||
VOID arcmsr_do_dpcQ(PACB pACB)
|
||
{
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_do_dpcQ................. \n");
|
||
#endif
|
||
/*
|
||
******************************************
|
||
******************************************
|
||
*/
|
||
while (pACB->dpcQ_head!=pACB->dpcQ_tail)
|
||
{
|
||
ULONG s;
|
||
DPC dpc;
|
||
|
||
/* got a "dpc routine" */
|
||
s=splcam();
|
||
dpc=pACB->dpcQ[pACB->dpcQ_head];
|
||
pACB->dpcQ_head++;
|
||
pACB->dpcQ_head %=ARCMSR_MAX_DPC;
|
||
splx(s);
|
||
/* execute this "dpc routine" */
|
||
dpc.dpcfun(dpc.arg);
|
||
}
|
||
return;
|
||
}
|
||
#if 0
|
||
/*
|
||
**********************************************************************
|
||
** <second> bit 05,04,03,02,01,00: 0 - 59
|
||
** <minute> bit 11,10,09,08,07,06: 0 - 59
|
||
** <month> bit 15,14,13,12: 1 - 12
|
||
** <hour> bit 21,20,19,18,17,16: 0 - 59
|
||
** <day> bit 26,25,24,23,22: 1 - 31
|
||
** <year> bit 31,30,29,28,27: 0=2000,31=2031
|
||
**********************************************************************
|
||
*/
|
||
ULONG arcmsr_make_timespec(ULONG year,ULONG mon,ULONG day,ULONG hour,ULONG min,ULONG sec)
|
||
{
|
||
return((year<<27)|(day<<22)|(hour<<16)|(mon<<12)|(min<<6)|(sec));
|
||
}
|
||
/*
|
||
********************************************************************
|
||
********************************************************************
|
||
*/
|
||
ULONG arcmsr_getcmos_time(VOID)
|
||
{
|
||
ULONG year,mon,day,hour,min,sec;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_getcmos_time \n");
|
||
#endif
|
||
sec=bcd2bin(rtcin(RTC_SEC));
|
||
min=bcd2bin(rtcin(RTC_MIN));
|
||
hour=bcd2bin(rtcin(RTC_HRS));
|
||
day=bcd2bin(rtcin(RTC_DAY));
|
||
mon=bcd2bin(rtcin(RTC_MONTH));
|
||
year=bcd2bin(rtcin(RTC_YEAR));
|
||
if((year +=1900) < 1970)
|
||
year +=100;
|
||
return arcmsr_make_timespec(year,mon,day,hour,min,sec);
|
||
}
|
||
#endif
|
||
/*
|
||
*********************************************************************************
|
||
** Asynchronous notification handler.
|
||
*********************************************************************************
|
||
*/
|
||
static VOID arcmsr_async(VOID *cb_arg, ULONG code, struct cam_path *path, VOID *arg)
|
||
{
|
||
PACB pACB;
|
||
UCHAR target_id,target_lun;
|
||
struct cam_sim *sim;
|
||
ULONG s;
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_async.......................................... \n");
|
||
#endif
|
||
s=splcam();
|
||
|
||
sim=(struct cam_sim *) cb_arg;
|
||
pACB =(PACB) 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);
|
||
}
|
||
/*
|
||
**************************************************************************
|
||
* arcmsr_do_thread_works
|
||
* execute programs schedule by kernel thread
|
||
* execute programs schedule by kernel thread
|
||
* :do background rebuilding
|
||
*
|
||
* tsleep(void *ident,int priority,const char *wmesg,int timo)
|
||
* tsleep()
|
||
* General sleep call. Suspends the current process until a wakeup is
|
||
* performed on the specified identifier. The process will then be made
|
||
* runnable with the specified priority. Sleeps at most timo/hz seconds
|
||
* (0 means no timeout). If pri includes PCATCH flag, signals are checked
|
||
* before and after sleeping, else signals are not checked. Returns 0 if
|
||
* awakened, EWOULDBLOCK if the timeout expires. If PCATCH is set and a
|
||
* signal needs to be delivered, ERESTART is returned if the current system
|
||
* call should be restarted if possible, and EINTR is returned if the system
|
||
* call should be interrupted by the signal (return EINTR).
|
||
*
|
||
* await(int priority, int timo)
|
||
* await() - wait for async condition to occur. The process blocks until
|
||
* wakeup() is called on the most recent asleep() address. If wakeup is called
|
||
* priority to await(), await() winds up being a NOP.
|
||
*
|
||
* If await() is called more then once (without an intervening asleep() call),
|
||
* await() is still effectively a NOP but it calls mi_switch() to give other
|
||
* processes some cpu before returning. The process is left runnable.
|
||
*
|
||
* <<<<<<<< EXPERIMENTAL, UNTESTED >>>>>>>>>>
|
||
* asleep(void *ident, int priority, const char *wmesg, int timo)
|
||
* asleep() - async sleep call. Place process on wait queue and return
|
||
* immediately without blocking. The process stays runnable until await()
|
||
* is called. If ident is NULL, remove process from wait queue if it is still
|
||
* on one.
|
||
*
|
||
* Only the most recent sleep condition is effective when making successive
|
||
* calls to asleep() or when calling tsleep().
|
||
*
|
||
* The timeout, if any, is not initiated until await() is called. The sleep
|
||
* priority, signal, and timeout is specified in the asleep() call but may be
|
||
* overriden in the await() call.
|
||
*
|
||
* <<<<<<<< EXPERIMENTAL, UNTESTED >>>>>>>>>>
|
||
* :do background rebuilding
|
||
***************************************************************************
|
||
*/
|
||
VOID arcmsr_do_thread_works(VOID *arg)
|
||
{
|
||
PACB pACB=(PACB) arg;
|
||
ARCMSR_LOCK_INIT(&pACB->arcmsr_kthread_lock, "arcmsr kthread lock");
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_do_thread_works................. \n");
|
||
#endif
|
||
|
||
ARCMSR_LOCK_ACQUIRE(&pACB->arcmsr_kthread_lock);
|
||
while(1)
|
||
{
|
||
tsleep((caddr_t)pACB->kthread_proc, PRIBIO | PWAIT, "arcmsr", hz/4);/*.25 sec*/
|
||
/*
|
||
** if do_dpcQ_semaphore is signal
|
||
** do following works
|
||
*/
|
||
arcmsr_do_dpcQ(pACB); /*see if there were some dpc routine need to execute*/
|
||
if(pACB->acb_flags & ACB_F_STOP_THREAD)
|
||
{
|
||
ARCMSR_LOCK_RELEASE(&pACB->arcmsr_kthread_lock);
|
||
break;
|
||
}
|
||
}
|
||
kthread_exit(0);
|
||
return;
|
||
}
|
||
/*
|
||
************************************************************************
|
||
**
|
||
**
|
||
************************************************************************
|
||
*/
|
||
VOID arcmsr_flush_adapter_cache(PACB pACB)
|
||
{
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_flush_adapter_cache..............\n");
|
||
#endif
|
||
CHIP_REG_WRITE32(&pACB->pmu->inbound_msgaddr0,ARCMSR_INBOUND_MESG0_FLUSH_CACHE);
|
||
return;
|
||
}
|
||
/*
|
||
**********************************************************************
|
||
**
|
||
**
|
||
**
|
||
**********************************************************************
|
||
*/
|
||
BOOLEAN arcmsr_wait_msgint_ready(PACB pACB)
|
||
{
|
||
ULONG Index;
|
||
UCHAR Retries=0x00;
|
||
do
|
||
{
|
||
for(Index=0; Index < 500000; Index++)
|
||
{
|
||
if(CHIP_REG_READ32(&pACB->pmu->outbound_intstatus) & ARCMSR_MU_OUTBOUND_MESSAGE0_INT)
|
||
{
|
||
CHIP_REG_WRITE32(&pACB->pmu->outbound_intstatus, ARCMSR_MU_OUTBOUND_MESSAGE0_INT);/*clear interrupt*/
|
||
return TRUE;
|
||
}
|
||
/* one us delay */
|
||
UDELAY(10);
|
||
}/*max 5 seconds*/
|
||
}while(Retries++ < 24);/*max 2 minutes*/
|
||
return FALSE;
|
||
}
|
||
/*
|
||
**********************************************************************
|
||
**
|
||
** Q back this SRB into ACB ArraySRB
|
||
**
|
||
**********************************************************************
|
||
*/
|
||
VOID arcmsr_srb_complete(PSRB pSRB)
|
||
{
|
||
ULONG s;
|
||
PACB pACB=pSRB->pACB;
|
||
union ccb *pccb=pSRB->pccb;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_srb_complete: pSRB=%p srb_doneindex=%x srb_startindex=%x\n",pSRB,pACB->srb_doneindex,pACB->srb_startindex);
|
||
#endif
|
||
|
||
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
|
||
**********************************************************************
|
||
*/
|
||
VOID arcmsr_report_SenseInfoBuffer(PSRB pSRB)
|
||
{
|
||
union ccb *pccb=pSRB->pccb;
|
||
PSENSE_DATA psenseBuffer=(PSENSE_DATA)&pccb->csio.sense_data;
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_report_SenseInfoBuffer...........\n");
|
||
#endif
|
||
|
||
pccb->ccb_h.status|=CAM_REQ_CMP;
|
||
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
|
||
*********************************************************************
|
||
*/
|
||
VOID arcmsr_queue_wait2go_srb(PACB pACB,PSRB pSRB)
|
||
{
|
||
ULONG s;
|
||
LONG i=0;
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_qtail_wait2go_srb:......................................... \n");
|
||
#endif
|
||
|
||
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;
|
||
}
|
||
/*
|
||
*********************************************************************
|
||
**
|
||
*********************************************************************
|
||
*/
|
||
VOID arcmsr_abort_allcmd(PACB pACB)
|
||
{
|
||
CHIP_REG_WRITE32(&pACB->pmu->inbound_msgaddr0,ARCMSR_INBOUND_MESG0_ABORT_CMD);
|
||
return;
|
||
}
|
||
|
||
/*
|
||
****************************************************************************
|
||
** Routine Description: Reset 80331 iop.
|
||
** Arguments:
|
||
** Return Value: Nothing.
|
||
****************************************************************************
|
||
*/
|
||
VOID arcmsr_iop_reset(PACB pACB)
|
||
{
|
||
PSRB pSRB,pfreesrb;
|
||
ULONG intmask_org,mask;
|
||
LONG i=0;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_iop_reset: reset iop controller......................................\n");
|
||
#endif
|
||
if(pACB->srboutstandingcount!=0)
|
||
{
|
||
/* Q back all outstanding srb into wait exec psrb Q*/
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_iop_reset: srboutstandingcount=%d ...\n",pACB->srboutstandingcount);
|
||
#endif
|
||
/* disable all outbound interrupt */
|
||
intmask_org=CHIP_REG_READ32(&pACB->pmu->outbound_intmask);
|
||
CHIP_REG_WRITE32(&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)!=TRUE)
|
||
{
|
||
printf("arcmsr_iop_reset: wait 'abort all outstanding command' timeout.................in \n");
|
||
}
|
||
/*clear all outbound posted Q*/
|
||
for(i=0;i<ARCMSR_MAX_OUTSTANDING_CMD;i++)
|
||
{
|
||
CHIP_REG_READ32(&pACB->pmu->outbound_queueport);
|
||
}
|
||
pfreesrb=pACB->pfreesrb;
|
||
for(i=0;i<ARCMSR_MAX_FREESRB_NUM;i++)
|
||
{
|
||
pSRB=&pfreesrb[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);
|
||
CHIP_REG_WRITE32(&pACB->pmu->outbound_intmask,intmask_org & mask);
|
||
atomic_set_int(&pACB->srboutstandingcount,0);
|
||
/* post abort all outstanding command message to RAID controller */
|
||
}
|
||
i=0;
|
||
while(pACB->srbwait2gocount > 0)
|
||
{
|
||
pSRB=pACB->psrbwait2go[i];
|
||
if(pSRB!=NULL)
|
||
{
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_iop_reset:abort command... srbwait2gocount=%d ...\n",pACB->srbwait2gocount);
|
||
#endif
|
||
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;
|
||
}
|
||
return;
|
||
}
|
||
/*
|
||
**********************************************************************
|
||
**
|
||
** PAGE_SIZE=4096 or 8192,PAGE_SHIFT=12
|
||
**********************************************************************
|
||
*/
|
||
VOID arcmsr_build_srb(PSRB pSRB, bus_dma_segment_t *dm_segs, LONG nseg)
|
||
{
|
||
PARCMSR_CDB pARCMSR_CDB=&pSRB->arcmsr_cdb;
|
||
PCHAR psge=(PCHAR)&pARCMSR_CDB->u;
|
||
ULONG address_lo,address_hi;
|
||
union ccb *pccb=pSRB->pccb;
|
||
struct ccb_scsiio *pcsio=&pccb->csio;
|
||
LONG arccdbsize=0x30;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_build_srb........................... \n");
|
||
#endif
|
||
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=(UCHAR)pcsio->cdb_len;
|
||
pARCMSR_CDB->Context=(CPT2INT)pARCMSR_CDB;
|
||
bcopy(pcsio->cdb_io.cdb_bytes, pARCMSR_CDB->Cdb, pcsio->cdb_len);
|
||
if(nseg != 0)
|
||
{
|
||
PACB pACB=pSRB->pACB;
|
||
bus_dmasync_op_t op;
|
||
LONG 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=(ULONG) 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)
|
||
{
|
||
PSG32ENTRY pdma_sg=(PSG32ENTRY)psge;
|
||
pdma_sg->address=address_lo;
|
||
pdma_sg->length=length;
|
||
psge += sizeof(SG32ENTRY);
|
||
arccdbsize += sizeof(SG32ENTRY);
|
||
}
|
||
else
|
||
{
|
||
LONG sg64s_size=0,tmplength=length;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_build_srb: !!!!!!!!!!!......address_hi=%x.... \n",address_hi);
|
||
#endif
|
||
while(1)
|
||
{
|
||
LONG64 span4G,length0;
|
||
PSG64ENTRY pdma_sg=(PSG64ENTRY)psge;
|
||
|
||
span4G=(LONG64)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=(ULONG)length0|IS_SG64_ADDR;
|
||
address_hi=address_hi+1;
|
||
address_lo=0;
|
||
tmplength=tmplength-(LONG)length0;
|
||
sg64s_size += sizeof(SG64ENTRY);
|
||
psge += sizeof(SG64ENTRY);
|
||
cdb_sgcount++;
|
||
}
|
||
else
|
||
{
|
||
pdma_sg->length=tmplength|IS_SG64_ADDR;
|
||
sg64s_size += sizeof(SG64ENTRY);
|
||
psge += sizeof(SG64ENTRY);
|
||
break;
|
||
}
|
||
}
|
||
arccdbsize += sg64s_size;
|
||
}
|
||
cdb_sgcount++;
|
||
}
|
||
pARCMSR_CDB->sgcount=(UCHAR)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);
|
||
}
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_build_srb: pSRB=%p cmd=%x xferlength=%d arccdbsize=%d sgcount=%d\n",pSRB,pcsio->cdb_io.cdb_bytes[0],pARCMSR_CDB->DataLength,arccdbsize,pARCMSR_CDB->sgcount);
|
||
#endif
|
||
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(PACB pACB,PSRB pSRB)
|
||
{
|
||
ULONG cdb_shifted_phyaddr=(ULONG) pSRB->cdb_shifted_phyaddr;
|
||
PARCMSR_CDB pARCMSR_CDB=(PARCMSR_CDB)&pSRB->arcmsr_cdb;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_post_srb: pSRB=%p cdb_shifted_phyaddr=%x\n",pSRB,cdb_shifted_phyaddr);
|
||
#endif
|
||
atomic_add_int(&pACB->srboutstandingcount,1);
|
||
pSRB->startdone=ARCMSR_SRB_START;
|
||
if(pARCMSR_CDB->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
|
||
{
|
||
CHIP_REG_WRITE32(&pACB->pmu->inbound_queueport,cdb_shifted_phyaddr|ARCMSR_SRBPOST_FLAG_SGL_BSIZE);
|
||
}
|
||
else
|
||
{
|
||
CHIP_REG_WRITE32(&pACB->pmu->inbound_queueport,cdb_shifted_phyaddr);
|
||
}
|
||
return;
|
||
}
|
||
/*
|
||
**************************************************************************
|
||
**
|
||
**
|
||
**************************************************************************
|
||
*/
|
||
VOID arcmsr_post_wait2go_srb(PACB pACB)
|
||
{
|
||
ULONG s;
|
||
PSRB pSRB;
|
||
LONG i=0;
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_post_wait2go_srb:srbwait2gocount=%d srboutstandingcount=%d\n",pACB->srbwait2gocount,pACB->srboutstandingcount);
|
||
#endif
|
||
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:
|
||
**********************************************************************
|
||
*/
|
||
VOID arcmsr_post_Qbuffer(PACB pACB)
|
||
{
|
||
ULONG s;
|
||
PUCHAR pQbuffer;
|
||
PQBUFFER pwbuffer=(PQBUFFER)&pACB->pmu->ioctl_wbuffer;
|
||
PUCHAR iop_data=(PUCHAR)pwbuffer->data;
|
||
LONG 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
|
||
*/
|
||
CHIP_REG_WRITE32(&pACB->pmu->inbound_doorbell,ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK);
|
||
splx(s);
|
||
return;
|
||
}
|
||
/*
|
||
************************************************************************
|
||
**
|
||
**
|
||
************************************************************************
|
||
*/
|
||
VOID arcmsr_stop_adapter_bgrb(PACB pACB)
|
||
{
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_stop_adapter_bgrb..............\n");
|
||
#endif
|
||
pACB->acb_flags |= ACB_F_MSG_STOP_BGRB;
|
||
pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
|
||
CHIP_REG_WRITE32(&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)
|
||
{
|
||
PACB pACB=(PACB)arg;
|
||
PSRB pSRB;
|
||
ULONG flagpsrb,outbound_intstatus,outbound_doorbell;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_interrupt..............\n");
|
||
#endif
|
||
/*
|
||
*********************************************
|
||
** check outbound intstatus <20>˹<CBB9>L<EFBFBD>l<EFBFBD>t<EFBFBD><74><EFBFBD><EFBFBD><EFBFBD>a
|
||
*********************************************
|
||
*/
|
||
outbound_intstatus=CHIP_REG_READ32(&pACB->pmu->outbound_intstatus) & pACB->outbound_int_enable;
|
||
CHIP_REG_WRITE32(&pACB->pmu->outbound_intstatus, outbound_intstatus);/*clear interrupt*/
|
||
if(outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT)
|
||
{
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_interrupt:..........ARCMSR_MU_OUTBOUND_DOORBELL_INT\n");
|
||
#endif
|
||
/*
|
||
*********************************************
|
||
** DOORBELL <20>m<EFBFBD><6D>! <20>O<EFBFBD>_<EFBFBD><5F><EFBFBD>l<EFBFBD><6C><EFBFBD>nñ<6E><C3B1>
|
||
*********************************************
|
||
*/
|
||
outbound_doorbell=CHIP_REG_READ32(&pACB->pmu->outbound_doorbell);
|
||
CHIP_REG_WRITE32(&pACB->pmu->outbound_doorbell,outbound_doorbell);/*clear interrupt */
|
||
if(outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK)
|
||
{
|
||
PQBUFFER prbuffer=(PQBUFFER)&pACB->pmu->ioctl_rbuffer;
|
||
PUCHAR iop_data=(PUCHAR)prbuffer->data;
|
||
PUCHAR pQbuffer;
|
||
LONG my_empty_len,iop_len,rqbuf_firstindex,rqbuf_lastindex;
|
||
ULONG s;
|
||
/*check this iop data if overflow my rqbuffer*/
|
||
s=splcam();
|
||
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--;
|
||
}
|
||
CHIP_REG_WRITE32(&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;
|
||
}
|
||
splx(s);
|
||
}
|
||
if(outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK)
|
||
{
|
||
ULONG s;
|
||
/*
|
||
*********************************************
|
||
** <20>ݬݬO<DDAC>_<EFBFBD>٦<EFBFBD><D9A6>l<EFBFBD><6C><EFBFBD>n<EFBFBD><6E><EFBFBD>D<EFBFBD>H<EFBFBD>X
|
||
*********************************************
|
||
*/
|
||
s=splcam();
|
||
if(pACB->wqbuf_firstindex!=pACB->wqbuf_lastindex)
|
||
{
|
||
PUCHAR pQbuffer;
|
||
PQBUFFER pwbuffer=(PQBUFFER)&pACB->pmu->ioctl_wbuffer;
|
||
PUCHAR iop_data=(PUCHAR)pwbuffer->data;
|
||
LONG 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
|
||
*/
|
||
CHIP_REG_WRITE32(&pACB->pmu->inbound_doorbell,ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK);
|
||
}
|
||
else
|
||
{
|
||
pACB->acb_flags |= ACB_F_IOCTL_WQBUFFER_CLEARED;
|
||
}
|
||
splx(s);
|
||
}
|
||
}
|
||
if(outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT)
|
||
{
|
||
/*
|
||
*****************************************************************************
|
||
** areca cdb command done
|
||
*****************************************************************************
|
||
*/
|
||
while(1)
|
||
{
|
||
if((flagpsrb=CHIP_REG_READ32(&pACB->pmu->outbound_queueport)) == 0xFFFFFFFF)
|
||
{
|
||
break;/*chip FIFO no srb for completion already*/
|
||
}
|
||
/* check if command done with no error*/
|
||
pSRB=(PSRB)(CINT2P)(pACB->vir2phy_offset+(flagpsrb << 5));/*frame must be 32 bytes aligned*/
|
||
if((pSRB->pACB!=pACB) || (pSRB->startdone!=ARCMSR_SRB_START))
|
||
{
|
||
if(pSRB->startdone==ARCMSR_SRB_ABORTED)
|
||
{
|
||
pSRB->pccb->ccb_h.status=CAM_REQ_ABORTED;
|
||
arcmsr_srb_complete(pSRB);
|
||
break;
|
||
}
|
||
printf("arcmsr_interrupt:got an illegal srb command done ...pACB=%p pSRB=%p srboutstandingcount=%d .....\n",pACB,pSRB,pACB->srboutstandingcount);
|
||
break;
|
||
}
|
||
if((flagpsrb & ARCMSR_SRBREPLY_FLAG_ERROR)==0)
|
||
{
|
||
pSRB->pccb->ccb_h.status=CAM_REQ_CMP;
|
||
arcmsr_srb_complete(pSRB);
|
||
}
|
||
else
|
||
{
|
||
switch(pSRB->arcmsr_cdb.DeviceStatus)
|
||
{
|
||
case ARCMSR_DEV_SELECT_TIMEOUT:
|
||
{
|
||
#if ARCMSR_DEBUG0
|
||
printf("pSRB=%p ......ARCMSR_DEV_SELECT_TIMEOUT\n",pSRB);
|
||
#endif
|
||
pSRB->pccb->ccb_h.status=CAM_SEL_TIMEOUT;
|
||
arcmsr_srb_complete(pSRB);
|
||
}
|
||
break;
|
||
case ARCMSR_DEV_ABORTED:
|
||
{
|
||
#if ARCMSR_DEBUG0
|
||
printf("pSRB=%p ......ARCMSR_DEV_ABORTED\n",pSRB);
|
||
#endif
|
||
pSRB->pccb->ccb_h.status=CAM_DEV_NOT_THERE;
|
||
arcmsr_srb_complete(pSRB);
|
||
}
|
||
break;
|
||
case ARCMSR_DEV_INIT_FAIL:
|
||
{
|
||
#if ARCMSR_DEBUG0
|
||
printf("pSRB=%p .....ARCMSR_DEV_INIT_FAIL\n",pSRB);
|
||
#endif
|
||
pSRB->pccb->ccb_h.status=CAM_DEV_NOT_THERE;
|
||
arcmsr_srb_complete(pSRB);
|
||
}
|
||
break;
|
||
case SCSISTAT_CHECK_CONDITION:
|
||
{
|
||
#if ARCMSR_DEBUG0
|
||
printf("pSRB=%p .....SCSISTAT_CHECK_CONDITION\n",pSRB);
|
||
#endif
|
||
arcmsr_report_SenseInfoBuffer(pSRB);
|
||
arcmsr_srb_complete(pSRB);
|
||
}
|
||
break;
|
||
default:
|
||
/* error occur Q all error srb to errorsrbpending Q*/
|
||
printf("arcmsr_interrupt:command error done ......but got unknow DeviceStatus=%x....\n",pSRB->arcmsr_cdb.DeviceStatus);
|
||
pSRB->pccb->ccb_h.status=CAM_UNCOR_PARITY;/*unknow error or crc error just for retry*/
|
||
arcmsr_srb_complete(pSRB);
|
||
break;
|
||
}
|
||
}
|
||
} /*drain reply FIFO*/
|
||
}
|
||
if(pACB->srbwait2gocount != 0)
|
||
{
|
||
arcmsr_post_wait2go_srb(pACB);/*try to post all pending srb*/
|
||
}
|
||
return;
|
||
}
|
||
/*
|
||
***********************************************************************
|
||
**
|
||
**int copyin __P((const void *udaddr, void *kaddr, size_t len));
|
||
**int copyout __P((const void *kaddr, void *udaddr, size_t len));
|
||
**
|
||
**ENOENT "" No such file or directory ""
|
||
**ENOIOCTL "" ioctl not handled by this layer ""
|
||
**ENOMEM "" Cannot allocate memory ""
|
||
**EINVAL "" Invalid argument ""
|
||
************************************************************************
|
||
*/
|
||
LONG arcmsr_iop_ioctlcmd(PACB pACB,ULONG ioctl_cmd,caddr_t arg)
|
||
{
|
||
PCMD_IO_CONTROL pccbioctl=(PCMD_IO_CONTROL) arg;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_iop_ioctlcmd................. \n");
|
||
#endif
|
||
|
||
if(memcmp(pccbioctl->Signature,"ARCMSR",6)!=0)
|
||
{
|
||
return EINVAL;
|
||
}
|
||
switch(ioctl_cmd)
|
||
{
|
||
case ARCMSR_IOCTL_READ_RQBUFFER:
|
||
{
|
||
ULONG s;
|
||
PCMD_IOCTL_FIELD pccbioctlfld=(PCMD_IOCTL_FIELD)arg;
|
||
PUCHAR pQbuffer,ptmpQbuffer=pccbioctlfld->ioctldatabuffer;
|
||
LONG allxfer_len=0;
|
||
|
||
s=splcam();
|
||
while((pACB->rqbuf_firstindex!=pACB->rqbuf_lastindex) && (allxfer_len<1031))
|
||
{
|
||
/*copy READ QBUFFER to srb*/
|
||
pQbuffer=&pACB->rqbuffer[pACB->rqbuf_firstindex];
|
||
memcpy(ptmpQbuffer,pQbuffer,1);
|
||
pACB->rqbuf_firstindex++;
|
||
pACB->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; /*if last index number set it to 0 */
|
||
ptmpQbuffer++;
|
||
allxfer_len++;
|
||
}
|
||
if(pACB->acb_flags & ACB_F_IOPDATA_OVERFLOW)
|
||
{
|
||
PQBUFFER prbuffer=(PQBUFFER)&pACB->pmu->ioctl_rbuffer;
|
||
PUCHAR pQbuffer;
|
||
PUCHAR iop_data=(PUCHAR)prbuffer->data;
|
||
LONG iop_len;
|
||
|
||
pACB->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
|
||
iop_len=(LONG)prbuffer->data_len;
|
||
/*this iop data does no chance to make me overflow again here, so just do it*/
|
||
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--;
|
||
}
|
||
CHIP_REG_WRITE32(&pACB->pmu->inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_READ_OK);/*signature, let IOP331 know data has been readed */
|
||
}
|
||
pccbioctl->Length=allxfer_len;
|
||
pccbioctl->ReturnCode=ARCMSR_IOCTL_RETURNCODE_OK;
|
||
splx(s);
|
||
return ARC_IOCTL_SUCCESS;
|
||
}
|
||
break;
|
||
case ARCMSR_IOCTL_WRITE_WQBUFFER:
|
||
{
|
||
ULONG s;
|
||
PCMD_IOCTL_FIELD pccbioctlfld=(PCMD_IOCTL_FIELD)arg;
|
||
LONG my_empty_len,user_len,wqbuf_firstindex,wqbuf_lastindex;
|
||
PUCHAR pQbuffer,ptmpuserbuffer=pccbioctlfld->ioctldatabuffer;
|
||
|
||
s=splcam();
|
||
user_len=pccbioctl->Length;
|
||
|
||
/*check if data xfer length of this request will overflow my array qbuffer */
|
||
wqbuf_lastindex=pACB->wqbuf_lastindex;
|
||
wqbuf_firstindex=pACB->wqbuf_firstindex;
|
||
my_empty_len=(wqbuf_firstindex-wqbuf_lastindex-1)&(ARCMSR_MAX_QBUFFER-1);
|
||
if(my_empty_len>=user_len)
|
||
{
|
||
while(user_len>0)
|
||
{
|
||
/*copy srb data to wqbuffer*/
|
||
pQbuffer=&pACB->wqbuffer[pACB->wqbuf_lastindex];
|
||
memcpy(pQbuffer,ptmpuserbuffer,1);
|
||
pACB->wqbuf_lastindex++;
|
||
pACB->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;/*if last index number set it to 0 */
|
||
ptmpuserbuffer++;
|
||
user_len--;
|
||
}
|
||
/*post fist Qbuffer*/
|
||
if(pACB->acb_flags & ACB_F_IOCTL_WQBUFFER_CLEARED)
|
||
{
|
||
pACB->acb_flags &=~ACB_F_IOCTL_WQBUFFER_CLEARED;
|
||
arcmsr_post_Qbuffer(pACB);
|
||
}
|
||
pccbioctl->ReturnCode=ARCMSR_IOCTL_RETURNCODE_OK;
|
||
}
|
||
else
|
||
{
|
||
pccbioctl->ReturnCode=ARCMSR_IOCTL_RETURNCODE_ERROR;
|
||
}
|
||
splx(s);
|
||
return ARC_IOCTL_SUCCESS;
|
||
}
|
||
break;
|
||
case ARCMSR_IOCTL_CLEAR_RQBUFFER:
|
||
{
|
||
ULONG s;
|
||
PUCHAR pQbuffer=pACB->rqbuffer;
|
||
s=splcam();
|
||
if(pACB->acb_flags & ACB_F_IOPDATA_OVERFLOW)
|
||
{
|
||
pACB->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
|
||
CHIP_REG_WRITE32(&pACB->pmu->inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_READ_OK);/*signature, let IOP331 know data has been readed */
|
||
}
|
||
pACB->acb_flags |= ACB_F_IOCTL_RQBUFFER_CLEARED;
|
||
pACB->rqbuf_firstindex=0;
|
||
pACB->rqbuf_lastindex=0;
|
||
memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
|
||
pccbioctl->ReturnCode=ARCMSR_IOCTL_RETURNCODE_OK;
|
||
splx(s);
|
||
return ARC_IOCTL_SUCCESS;
|
||
}
|
||
break;
|
||
case ARCMSR_IOCTL_CLEAR_WQBUFFER:
|
||
{
|
||
ULONG s;
|
||
PUCHAR pQbuffer=pACB->wqbuffer;
|
||
|
||
s=splcam();
|
||
if(pACB->acb_flags & ACB_F_IOPDATA_OVERFLOW)
|
||
{
|
||
pACB->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
|
||
CHIP_REG_WRITE32(&pACB->pmu->inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_READ_OK);/*signature, let IOP331 know data has been readed */
|
||
}
|
||
pACB->acb_flags |= ACB_F_IOCTL_WQBUFFER_CLEARED;
|
||
pACB->wqbuf_firstindex=0;
|
||
pACB->wqbuf_lastindex=0;
|
||
memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
|
||
pccbioctl->ReturnCode=ARCMSR_IOCTL_RETURNCODE_OK;
|
||
splx(s);
|
||
return ARC_IOCTL_SUCCESS;
|
||
}
|
||
break;
|
||
case ARCMSR_IOCTL_CLEAR_ALLQBUFFER:
|
||
{
|
||
ULONG s;
|
||
PUCHAR pQbuffer;
|
||
|
||
s=splcam();
|
||
if(pACB->acb_flags & ACB_F_IOPDATA_OVERFLOW)
|
||
{
|
||
pACB->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
|
||
CHIP_REG_WRITE32(&pACB->pmu->inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_READ_OK);/*signature, let IOP331 know data has been readed */
|
||
}
|
||
pACB->acb_flags |= (ACB_F_IOCTL_WQBUFFER_CLEARED|ACB_F_IOCTL_RQBUFFER_CLEARED);
|
||
pACB->rqbuf_firstindex=0;
|
||
pACB->rqbuf_lastindex=0;
|
||
pACB->wqbuf_firstindex=0;
|
||
pACB->wqbuf_lastindex=0;
|
||
pQbuffer=pACB->rqbuffer;
|
||
memset(pQbuffer, 0, sizeof(struct _QBUFFER));
|
||
pQbuffer=pACB->wqbuffer;
|
||
memset(pQbuffer, 0, sizeof(struct _QBUFFER));
|
||
pccbioctl->ReturnCode=ARCMSR_IOCTL_RETURNCODE_OK;
|
||
splx(s);
|
||
return ARC_IOCTL_SUCCESS;
|
||
}
|
||
break;
|
||
case ARCMSR_IOCTL_RETURN_CODE_3F:
|
||
{
|
||
pccbioctl->ReturnCode=ARCMSR_IOCTL_RETURNCODE_3F;
|
||
return ARC_IOCTL_SUCCESS;
|
||
}
|
||
break;
|
||
case ARCMSR_IOCTL_SAY_HELLO:
|
||
{
|
||
PCMD_IOCTL_FIELD pccbioctlfld=(PCMD_IOCTL_FIELD)arg;
|
||
PCHAR hello_string="Hello! I am ARCMSR";
|
||
PCHAR puserbuffer=(PUCHAR)pccbioctlfld->ioctldatabuffer;
|
||
|
||
if(memcpy(puserbuffer,hello_string,(SHORT)strlen(hello_string)))
|
||
{
|
||
pccbioctl->ReturnCode=ARCMSR_IOCTL_RETURNCODE_ERROR;
|
||
return ENOIOCTL;
|
||
}
|
||
pccbioctl->ReturnCode=ARCMSR_IOCTL_RETURNCODE_OK;
|
||
return ARC_IOCTL_SUCCESS;
|
||
}
|
||
break;
|
||
}
|
||
return EINVAL;
|
||
}
|
||
/*
|
||
**************************************************************************
|
||
**
|
||
**************************************************************************
|
||
*/
|
||
PSRB arcmsr_get_freesrb(PACB pACB)
|
||
{
|
||
PSRB pSRB=NULL;
|
||
ULONG s;
|
||
LONG srb_startindex,srb_doneindex;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_get_freesrb: srb_startindex=%d srb_doneindex=%d\n",pACB->srb_startindex,pACB->srb_doneindex);
|
||
#endif
|
||
|
||
s=splcam();
|
||
srb_doneindex=pACB->srb_doneindex;
|
||
srb_startindex=pACB->srb_startindex;
|
||
pSRB=pACB->psrbringQ[srb_startindex];
|
||
srb_startindex++;
|
||
srb_startindex %= ARCMSR_MAX_FREESRB_NUM;
|
||
if(srb_doneindex!=srb_startindex)
|
||
{
|
||
pACB->srb_startindex=srb_startindex;
|
||
}
|
||
else
|
||
{
|
||
pSRB=NULL;
|
||
}
|
||
splx(s);
|
||
return(pSRB);
|
||
}
|
||
/*
|
||
*********************************************************************
|
||
**
|
||
**
|
||
**
|
||
*********************************************************************
|
||
*/
|
||
static VOID arcmsr_executesrb(VOID *arg,bus_dma_segment_t *dm_segs,LONG nseg,LONG error)
|
||
{
|
||
PSRB pSRB=(PSRB)arg;
|
||
PACB pACB;
|
||
union ccb *pccb;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_executesrb........................................ \n" );
|
||
#endif
|
||
|
||
pccb=pSRB->pccb;
|
||
pACB=(PACB)pSRB->pACB;
|
||
if(error != 0)
|
||
{
|
||
if(error != EFBIG)
|
||
{
|
||
printf("arcmsr_executesrb:%d Unexepected error %x returned from " "bus_dmamap_load\n",pACB->pci_unit,error);
|
||
}
|
||
if(pccb->ccb_h.status == CAM_REQ_INPROG)
|
||
{
|
||
xpt_freeze_devq(pccb->ccb_h.path,/*count*/1);
|
||
pccb->ccb_h.status=CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
|
||
}
|
||
xpt_done(pccb);
|
||
return;
|
||
}
|
||
arcmsr_build_srb(pSRB,dm_segs,nseg);
|
||
if(pccb->ccb_h.status != CAM_REQ_INPROG)
|
||
{
|
||
if(nseg != 0)
|
||
{
|
||
bus_dmamap_unload(pACB->buffer_dmat,pSRB->dmamap);
|
||
}
|
||
xpt_done(pccb);
|
||
return;
|
||
}
|
||
pccb->ccb_h.status |= CAM_SIM_QUEUED;
|
||
if(pACB->srboutstandingcount < ARCMSR_MAX_OUTSTANDING_CMD)
|
||
{
|
||
/*
|
||
******************************************************************
|
||
** and we can make sure there were no pending srb in this duration
|
||
******************************************************************
|
||
*/
|
||
arcmsr_post_srb(pACB,pSRB);
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
******************************************************************
|
||
** Q of srbwaitexec will be post out when any outstanding command complete
|
||
******************************************************************
|
||
*/
|
||
arcmsr_queue_wait2go_srb(pACB,pSRB);
|
||
}
|
||
return;
|
||
}
|
||
/*
|
||
*****************************************************************************************
|
||
**
|
||
*****************************************************************************************
|
||
*/
|
||
BOOLEAN arcmsr_seek_cmd2abort(union ccb * pabortccb)
|
||
{
|
||
PSRB pSRB,pfreesrb;
|
||
PACB pACB=(PACB) pabortccb->ccb_h.arcmsr_ccbacb_ptr;
|
||
ULONG s,intmask_org,mask;
|
||
LONG i=0;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_seek_cmd2abort.................. \n");
|
||
#endif
|
||
|
||
s=splcam();
|
||
/*
|
||
** It is the upper layer do abort command this lock just prior to calling us.
|
||
** First determine if we currently own this command.
|
||
** Start by searching the device queue. If not found
|
||
** at all,and the system wanted us to just abort the
|
||
** command return success.
|
||
*/
|
||
if(pACB->srboutstandingcount!=0)
|
||
{
|
||
/* Q back all outstanding srb into wait exec psrb Q*/
|
||
pfreesrb=pACB->pfreesrb;
|
||
for(i=0;i<ARCMSR_MAX_FREESRB_NUM;i++)
|
||
{
|
||
pSRB=&pfreesrb[i];
|
||
if(pSRB->startdone==ARCMSR_SRB_START)
|
||
{
|
||
if(pSRB->pccb==pabortccb)
|
||
{
|
||
/* disable all outbound interrupt */
|
||
intmask_org=CHIP_REG_READ32(&pACB->pmu->outbound_intmask);
|
||
CHIP_REG_WRITE32(&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)!=TRUE)
|
||
{
|
||
printf("arcmsr_seek_cmd2abort: wait 'abort all outstanding command' timeout.................in \n");
|
||
}
|
||
/*clear all outbound posted Q*/
|
||
for(i=0;i<ARCMSR_MAX_OUTSTANDING_CMD;i++)
|
||
{
|
||
CHIP_REG_READ32(&pACB->pmu->outbound_queueport);
|
||
}
|
||
pfreesrb=pACB->pfreesrb;
|
||
for(i=0;i<ARCMSR_MAX_FREESRB_NUM;i++)
|
||
{
|
||
pSRB=&pfreesrb[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);
|
||
CHIP_REG_WRITE32(&pACB->pmu->outbound_intmask,intmask_org & mask);
|
||
splx(s);
|
||
return(TRUE);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
/*
|
||
** seek this command at our command list
|
||
** if command found then remove,abort it and free this SRB
|
||
*/
|
||
if(pACB->srbwait2gocount!=0)
|
||
{
|
||
for(i=0;i<ARCMSR_MAX_OUTSTANDING_CMD;i++)
|
||
{
|
||
pSRB=pACB->psrbwait2go[i];
|
||
if(pSRB!=NULL)
|
||
{
|
||
if(pSRB->pccb==pabortccb)
|
||
{
|
||
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);
|
||
splx(s);
|
||
return(TRUE);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
splx(s);
|
||
return (FALSE);
|
||
}
|
||
/*
|
||
****************************************************************************
|
||
**
|
||
****************************************************************************
|
||
*/
|
||
VOID arcmsr_bus_reset(PACB pACB)
|
||
{
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_bus_reset.......................... \n");
|
||
#endif
|
||
|
||
arcmsr_iop_reset(pACB);
|
||
return;
|
||
}
|
||
/*
|
||
*********************************************************************
|
||
**
|
||
** 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;
|
||
**
|
||
**union ccb {
|
||
** struct ccb_hdr ccb_h; For convenience
|
||
** struct ccb_scsiio csio;
|
||
** struct ccb_getdev cgd;
|
||
** struct ccb_getdevlist cgdl;
|
||
** struct ccb_pathinq cpi;
|
||
** struct ccb_relsim crs;
|
||
** struct ccb_setasync csa;
|
||
** struct ccb_setdev csd;
|
||
** struct ccb_pathstats cpis;
|
||
** struct ccb_getdevstats cgds;
|
||
** struct ccb_dev_match cdm;
|
||
** struct ccb_trans_settings cts;
|
||
** struct ccb_calc_geometry ccg;
|
||
** struct ccb_abort cab;
|
||
** struct ccb_resetbus crb;
|
||
** struct ccb_resetdev crd;
|
||
** struct ccb_termio tio;
|
||
** struct ccb_accept_tio atio;
|
||
** struct ccb_scsiio ctio;
|
||
** struct ccb_en_lun cel;
|
||
** struct ccb_immed_notify cin;
|
||
** struct ccb_notify_ack cna;
|
||
** struct ccb_eng_inq cei;
|
||
** struct ccb_eng_exec cee;
|
||
** struct ccb_rescan crcn;
|
||
** struct ccb_debug cdbg;
|
||
** }
|
||
**
|
||
**struct ccb_hdr {
|
||
** cam_pinfo pinfo; "" Info for priority scheduling
|
||
** camq_entry xpt_links; "" For chaining in the XPT layer
|
||
** camq_entry sim_links; "" For chaining in the SIM layer
|
||
** camq_entry periph_links; "" For chaining in the type driver
|
||
** u_int32_t retry_count;
|
||
** void (*cbfcnp)(struct cam_periph *, union ccb *);"" Callback on completion function
|
||
** xpt_opcode func_code; "" XPT function code
|
||
** u_int32_t status; "" Status returned by CAM subsystem
|
||
** struct cam_path *path; "" Compiled path for this ccb
|
||
** path_id_t path_id; "" Path ID for the request
|
||
** target_id_t target_id; "" Target device ID
|
||
** lun_id_t target_lun; "" Target LUN number
|
||
** u_int32_t flags;
|
||
** ccb_ppriv_area periph_priv;
|
||
** ccb_spriv_area sim_priv;
|
||
** u_int32_t timeout; "" Timeout value
|
||
** struct callout_handle timeout_ch; "" Callout handle used for timeouts
|
||
**};
|
||
**
|
||
**typedef union {
|
||
** u_int8_t *cdb_ptr; "" Pointer to the CDB bytes to send
|
||
** u_int8_t cdb_bytes[IOCDBLEN]; "" Area for the CDB send
|
||
**} cdb_t;
|
||
**
|
||
** SCSI I/O Request CCB used for the XPT_SCSI_IO and XPT_CONT_TARGET_IO
|
||
** function codes.
|
||
**
|
||
**struct ccb_scsiio {
|
||
** struct ccb_hdr ccb_h;
|
||
** union ccb *next_ccb; "" Ptr for next CCB for action
|
||
** u_int8_t *req_map; "" Ptr to mapping info
|
||
** u_int8_t *data_ptr; "" Ptr to the data buf/SG list
|
||
** u_int32_t dxfer_len; "" Data transfer length
|
||
** struct scsi_sense_data sense_data; "" Autosense storage
|
||
** u_int8_t sense_len; "" Number of bytes to autosense
|
||
** u_int8_t cdb_len; "" Number of bytes for the CDB
|
||
** u_int16_t sglist_cnt; "" Number of SG list entries
|
||
** u_int8_t scsi_status; "" Returned SCSI status
|
||
** u_int8_t sense_resid; "" Autosense resid length: 2's comp
|
||
** u_int32_t resid; "" Transfer residual length: 2's comp
|
||
** cdb_t cdb_io; "" Union for CDB bytes/pointer
|
||
** u_int8_t *msg_ptr; "" Pointer to the message buffer
|
||
** u_int16_t msg_len; "" Number of bytes for the Message
|
||
** u_int8_t tag_action; "" What to do for tag queueing
|
||
**#define CAM_TAG_ACTION_NONE 0x00 "" The tag action should be either the define below (to send a non-tagged transaction) or one of the defined scsi tag messages from scsi_message.h.
|
||
** u_int tag_id; "" tag id from initator (target mode)
|
||
** u_int init_id; "" initiator id of who selected
|
||
**}
|
||
*********************************************************************
|
||
*/
|
||
static VOID arcmsr_action(struct cam_sim * psim,union ccb * pccb)
|
||
{
|
||
PACB pACB;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_action ..................................\n" );
|
||
#endif
|
||
|
||
pACB=(PACB) cam_sim_softc(psim);
|
||
if(pACB==NULL)
|
||
{
|
||
pccb->ccb_h.status=CAM_REQ_INVALID;
|
||
xpt_done(pccb);
|
||
return;
|
||
}
|
||
switch (pccb->ccb_h.func_code)
|
||
{
|
||
case XPT_SCSI_IO:
|
||
{
|
||
PSRB pSRB;
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_action: XPT_SCSI_IO......................\n" );
|
||
#endif
|
||
|
||
if((pSRB=arcmsr_get_freesrb(pACB)) == NULL)
|
||
{
|
||
pccb->ccb_h.status=CAM_RESRC_UNAVAIL;
|
||
xpt_done(pccb);
|
||
return;
|
||
}
|
||
pccb->ccb_h.arcmsr_ccbsrb_ptr=pSRB;
|
||
pccb->ccb_h.arcmsr_ccbacb_ptr=pACB;
|
||
pSRB->pccb=pccb;
|
||
if((pccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
|
||
{
|
||
if((pccb->ccb_h.flags & CAM_SCATTER_VALID) == 0)
|
||
{
|
||
if((pccb->ccb_h.flags & CAM_DATA_PHYS) == 0)
|
||
{
|
||
LONG error,s;
|
||
|
||
s=splsoftvm();
|
||
error = bus_dmamap_load(pACB->buffer_dmat,pSRB->dmamap,pccb->csio.data_ptr,pccb->csio.dxfer_len,arcmsr_executesrb,pSRB,/*flags*/0);
|
||
if(error == EINPROGRESS)
|
||
{
|
||
xpt_freeze_simq(pACB->psim,1);
|
||
pccb->ccb_h.status |= CAM_RELEASE_SIMQ;
|
||
}
|
||
splx(s);
|
||
}
|
||
else
|
||
{
|
||
panic("arcmsr: CAM_DATA_PHYS not supported");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
struct bus_dma_segment *segs;
|
||
|
||
if((pccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0 || (pccb->ccb_h.flags & CAM_DATA_PHYS) != 0)
|
||
{
|
||
pccb->ccb_h.status=CAM_PROVIDE_FAIL;
|
||
xpt_done(pccb);
|
||
free(pSRB,M_DEVBUF);
|
||
return;
|
||
}
|
||
segs=(struct bus_dma_segment *)pccb->csio.data_ptr;
|
||
arcmsr_executesrb(pSRB,segs,pccb->csio.sglist_cnt,0);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
arcmsr_executesrb(pSRB,NULL,0,0);
|
||
}
|
||
break;
|
||
}
|
||
case XPT_TARGET_IO:
|
||
{
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_action: XPT_TARGET_IO\n" );
|
||
#endif
|
||
/*
|
||
** target mode not yet support vendor specific commands.
|
||
*/
|
||
pccb->ccb_h.status=CAM_REQ_CMP;
|
||
xpt_done(pccb);
|
||
break;
|
||
}
|
||
case XPT_PATH_INQ:
|
||
{
|
||
struct ccb_pathinq *cpi=&pccb->cpi;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_action: XPT_PATH_INQ\n" );
|
||
#endif
|
||
cpi->version_num=1;
|
||
cpi->hba_inquiry=PI_SDTR_ABLE | PI_TAG_ABLE;
|
||
cpi->target_sprt=0;
|
||
cpi->hba_misc=0;
|
||
cpi->hba_eng_cnt=0;
|
||
cpi->max_target=ARCMSR_MAX_TARGETID;
|
||
cpi->max_lun=ARCMSR_MAX_TARGETLUN; /* 7 or 0 */
|
||
cpi->initiator_id=ARCMSR_SCSI_INITIATOR_ID;
|
||
cpi->bus_id=cam_sim_bus(psim);
|
||
strncpy(cpi->sim_vid,"FreeBSD",SIM_IDLEN);
|
||
strncpy(cpi->hba_vid,"ARCMSR",HBA_IDLEN);
|
||
strncpy(cpi->dev_name,cam_sim_name(psim),DEV_IDLEN);
|
||
cpi->unit_number=cam_sim_unit(psim);
|
||
cpi->ccb_h.status=CAM_REQ_CMP;
|
||
xpt_done(pccb);
|
||
break;
|
||
}
|
||
case XPT_ABORT:
|
||
{
|
||
union ccb *pabort_ccb;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_action: XPT_ABORT\n" );
|
||
#endif
|
||
pabort_ccb=pccb->cab.abort_ccb;
|
||
switch (pabort_ccb->ccb_h.func_code)
|
||
{
|
||
case XPT_ACCEPT_TARGET_IO:
|
||
case XPT_IMMED_NOTIFY:
|
||
case XPT_CONT_TARGET_IO:
|
||
if(arcmsr_seek_cmd2abort(pabort_ccb)==TRUE)
|
||
{
|
||
pabort_ccb->ccb_h.status=CAM_REQ_ABORTED;
|
||
xpt_done(pabort_ccb);
|
||
pccb->ccb_h.status=CAM_REQ_CMP;
|
||
}
|
||
else
|
||
{
|
||
xpt_print_path(pabort_ccb->ccb_h.path);
|
||
printf("Not found\n");
|
||
pccb->ccb_h.status=CAM_PATH_INVALID;
|
||
}
|
||
break;
|
||
case XPT_SCSI_IO:
|
||
pccb->ccb_h.status=CAM_UA_ABORT;
|
||
break;
|
||
default:
|
||
pccb->ccb_h.status=CAM_REQ_INVALID;
|
||
break;
|
||
}
|
||
xpt_done(pccb);
|
||
break;
|
||
}
|
||
case XPT_RESET_BUS:
|
||
case XPT_RESET_DEV:
|
||
{
|
||
LONG i;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_action: XPT_RESET_BUS\n" );
|
||
#endif
|
||
arcmsr_bus_reset(pACB);
|
||
for (i=0; i < 500; i++)
|
||
{
|
||
DELAY(1000);
|
||
}
|
||
pccb->ccb_h.status=CAM_REQ_CMP;
|
||
xpt_done(pccb);
|
||
break;
|
||
}
|
||
case XPT_TERM_IO:
|
||
{
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_action: XPT_TERM_IO\n" );
|
||
#endif
|
||
pccb->ccb_h.status=CAM_REQ_INVALID;
|
||
xpt_done(pccb);
|
||
break;
|
||
}
|
||
case XPT_GET_TRAN_SETTINGS:
|
||
{
|
||
struct ccb_trans_settings *cts;
|
||
ULONG s;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_action: XPT_GET_TRAN_SETTINGS\n" );
|
||
#endif
|
||
|
||
cts=&pccb->cts;
|
||
s=splcam();
|
||
cts->flags=(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB);
|
||
cts->sync_period=3;
|
||
cts->sync_offset=32;
|
||
cts->bus_width=MSG_EXT_WDTR_BUS_16_BIT;
|
||
cts->valid=CCB_TRANS_SYNC_RATE_VALID | CCB_TRANS_SYNC_OFFSET_VALID | CCB_TRANS_BUS_WIDTH_VALID | CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
|
||
splx(s);
|
||
pccb->ccb_h.status=CAM_REQ_CMP;
|
||
xpt_done(pccb);
|
||
break;
|
||
}
|
||
case XPT_SET_TRAN_SETTINGS:
|
||
{
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_action: XPT_SET_TRAN_SETTINGS\n" );
|
||
#endif
|
||
pccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
|
||
xpt_done(pccb);
|
||
break;
|
||
}
|
||
case XPT_CALC_GEOMETRY:
|
||
{
|
||
struct ccb_calc_geometry *ccg;
|
||
ULONG size_mb;
|
||
ULONG secs_per_cylinder;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_action: XPT_CALC_GEOMETRY\n" );
|
||
#endif
|
||
ccg=&pccb->ccg;
|
||
size_mb=ccg->volume_size/((1024L * 1024L)/ccg->block_size);
|
||
if(size_mb > 1024 )
|
||
{
|
||
ccg->heads=255;
|
||
ccg->secs_per_track=63;
|
||
}
|
||
else
|
||
{
|
||
ccg->heads=64;
|
||
ccg->secs_per_track=32;
|
||
}
|
||
secs_per_cylinder=ccg->heads * ccg->secs_per_track;
|
||
ccg->cylinders=ccg->volume_size / secs_per_cylinder;
|
||
pccb->ccb_h.status=CAM_REQ_CMP;
|
||
xpt_done(pccb);
|
||
break;
|
||
}
|
||
default:
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_action: invalid XPT function CAM_REQ_INVALID\n" );
|
||
#endif
|
||
pccb->ccb_h.status=CAM_REQ_INVALID;
|
||
xpt_done(pccb);
|
||
break;
|
||
}
|
||
return;
|
||
}
|
||
/*
|
||
**********************************************************************
|
||
**
|
||
** start background rebulid
|
||
**
|
||
**********************************************************************
|
||
*/
|
||
VOID arcmsr_start_adapter_bgrb(PACB pACB)
|
||
{
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_start_adapter_bgrb.................................. \n");
|
||
#endif
|
||
pACB->acb_flags |= ACB_F_MSG_START_BGRB;
|
||
pACB->acb_flags &= ~ACB_F_MSG_STOP_BGRB;
|
||
CHIP_REG_WRITE32(&pACB->pmu->inbound_msgaddr0,ARCMSR_INBOUND_MESG0_START_BGRB);
|
||
return;
|
||
}
|
||
/*
|
||
**********************************************************************
|
||
**
|
||
** start background rebulid
|
||
**
|
||
**********************************************************************
|
||
*/
|
||
VOID arcmsr_iop_init(PACB pACB)
|
||
{
|
||
ULONG intmask_org,mask,outbound_doorbell,firmware_state=0;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_iop_init.................................. \n");
|
||
#endif
|
||
do
|
||
{
|
||
firmware_state=CHIP_REG_READ32(&pACB->pmu->outbound_msgaddr1);
|
||
}while((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK)==0);
|
||
/* disable all outbound interrupt */
|
||
intmask_org=CHIP_REG_READ32(&pACB->pmu->outbound_intmask);
|
||
CHIP_REG_WRITE32(&pACB->pmu->outbound_intmask,intmask_org|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE);
|
||
/*start background rebuild*/
|
||
arcmsr_start_adapter_bgrb(pACB);
|
||
if(arcmsr_wait_msgint_ready(pACB)!=TRUE)
|
||
{
|
||
printf("arcmsr_HwInitialize: wait 'start adapter background rebulid' timeout................. \n");
|
||
}
|
||
/* clear Qbuffer if door bell ringed */
|
||
outbound_doorbell=CHIP_REG_READ32(&pACB->pmu->outbound_doorbell);
|
||
if(outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK)
|
||
{
|
||
CHIP_REG_WRITE32(&pACB->pmu->outbound_doorbell,outbound_doorbell);/*clear interrupt */
|
||
CHIP_REG_WRITE32(&pACB->pmu->inbound_doorbell,ARCMSR_INBOUND_DRIVER_DATA_READ_OK);
|
||
}
|
||
/* enable outbound Post Queue,outbound message0,outbell doorbell Interrupt */
|
||
mask=~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE|ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE|ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE);
|
||
CHIP_REG_WRITE32(&pACB->pmu->outbound_intmask,intmask_org & mask);
|
||
pACB->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
|
||
pACB->acb_flags |=ACB_F_IOP_INITED;
|
||
return;
|
||
}
|
||
/*
|
||
**********************************************************************
|
||
**
|
||
** map freesrb
|
||
**
|
||
**********************************************************************
|
||
*/
|
||
static void arcmsr_map_freesrb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
|
||
{
|
||
PACB pACB=arg;
|
||
PSRB psrb_tmp,pfreesrb;
|
||
ULONG cdb_phyaddr;
|
||
LONG i;
|
||
|
||
pfreesrb=(PSRB)pACB->uncacheptr;
|
||
cdb_phyaddr=segs->ds_addr; /* We suppose bus_addr_t high part always 0 here*/
|
||
if(((CPT2INT)pACB->uncacheptr & 0x1F)!=0)
|
||
{
|
||
pfreesrb=pfreesrb+(0x20-((CPT2INT)pfreesrb & 0x1F));
|
||
cdb_phyaddr=cdb_phyaddr+(0x20-((CPT2INT)cdb_phyaddr & 0x1F));
|
||
}
|
||
/*
|
||
********************************************************************
|
||
** here we need to tell iop 331 our freesrb.HighPart
|
||
** if freesrb.HighPart is not zero
|
||
********************************************************************
|
||
*/
|
||
for(i=0;i<ARCMSR_MAX_FREESRB_NUM;i++)
|
||
{
|
||
psrb_tmp=&pfreesrb[i];
|
||
if(((CPT2INT)psrb_tmp & 0x1F)==0) /*srb address must 32 (0x20) boundary*/
|
||
{
|
||
if(bus_dmamap_create(pACB->buffer_dmat, /*flags*/0, &psrb_tmp->dmamap)!=0)
|
||
{
|
||
pACB->acb_flags |= ACB_F_MAPFREESRB_FAILD;
|
||
printf(" arcmsr_map_freesrb: (pSRB->dmamap) bus_dmamap_create ..............error\n");
|
||
return;
|
||
}
|
||
psrb_tmp->cdb_shifted_phyaddr=cdb_phyaddr >> 5;
|
||
psrb_tmp->pACB=pACB;
|
||
pACB->psrbringQ[i]=psrb_tmp;
|
||
cdb_phyaddr=cdb_phyaddr+sizeof(struct _SRB);
|
||
}
|
||
else
|
||
{
|
||
pACB->acb_flags |= ACB_F_MAPFREESRB_FAILD;
|
||
printf(" arcmsr_map_freesrb:pfreesrb=%p i=%d this srb cross 32 bytes boundary ignored ......psrb_tmp=%p \n",pfreesrb,i,psrb_tmp);
|
||
return;
|
||
}
|
||
}
|
||
pACB->pfreesrb=pfreesrb;
|
||
pACB->vir2phy_offset=(CPT2INT)psrb_tmp-(cdb_phyaddr-sizeof(struct _SRB));
|
||
return;
|
||
}
|
||
/*
|
||
************************************************************************
|
||
**
|
||
**
|
||
************************************************************************
|
||
*/
|
||
VOID arcmsr_free_resource(PACB pACB)
|
||
{
|
||
/* remove the control device */
|
||
if (pACB->ioctl_dev != NULL)
|
||
{
|
||
destroy_dev(pACB->ioctl_dev);
|
||
}
|
||
bus_dmamap_unload(pACB->srb_dmat, pACB->srb_dmamap);
|
||
bus_dmamap_destroy(pACB->srb_dmat, pACB->srb_dmamap);
|
||
bus_dma_tag_destroy(pACB->srb_dmat);
|
||
bus_dma_tag_destroy(pACB->buffer_dmat);
|
||
bus_dma_tag_destroy(pACB->parent_dmat);
|
||
return;
|
||
}
|
||
/*
|
||
************************************************************************
|
||
** PCI config header registers for all devices
|
||
**
|
||
** #define PCIR_COMMAND 0x04
|
||
** #define PCIM_CMD_PORTEN 0x0001
|
||
** #define PCIM_CMD_MEMEN 0x0002
|
||
** #define PCIM_CMD_BUSMASTEREN 0x0004
|
||
** #define PCIM_CMD_MWRICEN 0x0010
|
||
** #define PCIM_CMD_PERRESPEN 0x0040
|
||
**
|
||
** Function : arcmsr_initialize
|
||
** Purpose : initialize the internal structures for a given SCSI host
|
||
** Inputs : host - pointer to this host adapter's structure
|
||
** Preconditions : when this function is called,the chip_type
|
||
** field of the pACB structure MUST have been set.
|
||
**
|
||
** 10h Base Address register #0
|
||
** 14h Base Address register #1
|
||
** 18h Base Address register #2
|
||
** 1Ch Base Address register #3
|
||
** 20h Base Address register #4
|
||
** 24h Base Address register #5
|
||
************************************************************************
|
||
*/
|
||
static LONG arcmsr_initialize(device_t dev)
|
||
{
|
||
PACB pACB=device_get_softc(dev);
|
||
LONG rid=PCI_BASE_ADDR0;
|
||
vm_offset_t mem_base;
|
||
USHORT pci_command;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_initialize..............................\n");
|
||
#endif
|
||
#if __FreeBSD_version >= 502010
|
||
if (bus_dma_tag_create( /*parent*/NULL,
|
||
/*alignemnt*/1,
|
||
/*boundary*/0,
|
||
/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
|
||
/*highaddr*/BUS_SPACE_MAXADDR,
|
||
/*filter*/NULL,
|
||
/*filterarg*/NULL,
|
||
/*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
|
||
/*nsegments*/BUS_SPACE_UNRESTRICTED,
|
||
/*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
|
||
/*flags*/0,
|
||
/*lockfunc*/NULL,
|
||
/*lockarg*/NULL,
|
||
&pACB->parent_dmat) != 0)
|
||
#else
|
||
if (bus_dma_tag_create( /*parent*/NULL,
|
||
/*alignemnt*/1,
|
||
/*boundary*/0,
|
||
/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
|
||
/*highaddr*/BUS_SPACE_MAXADDR,
|
||
/*filter*/NULL,
|
||
/*filterarg*/NULL,
|
||
/*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
|
||
/*nsegments*/BUS_SPACE_UNRESTRICTED,
|
||
/*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
|
||
/*flags*/0,
|
||
&pACB->parent_dmat) != 0)
|
||
#endif
|
||
{
|
||
printf("arcmsr_initialize: bus_dma_tag_create .......................failure!\n");
|
||
return ENOMEM;
|
||
}
|
||
/* Create a single tag describing a region large enough to hold all of the s/g lists we will need. */
|
||
#if __FreeBSD_version >= 502010
|
||
if(bus_dma_tag_create( /*parent_dmat*/pACB->parent_dmat,
|
||
/*alignment*/1,
|
||
/*boundary*/0,
|
||
/*lowaddr*/BUS_SPACE_MAXADDR,
|
||
/*highaddr*/BUS_SPACE_MAXADDR,
|
||
/*filter*/NULL,
|
||
/*filterarg*/NULL,
|
||
/*maxsize*/MAXBSIZE,
|
||
/*nsegments*/ARCMSR_MAX_SG_ENTRIES,
|
||
/*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
|
||
/*flags*/BUS_DMA_ALLOCNOW,
|
||
/*lockfunc*/busdma_lock_mutex,
|
||
/*lockarg*/&Giant,
|
||
&pACB->buffer_dmat) != 0)
|
||
#else
|
||
if(bus_dma_tag_create( /*parent_dmat*/pACB->parent_dmat,
|
||
/*alignment*/1,
|
||
/*boundary*/0,
|
||
/*lowaddr*/BUS_SPACE_MAXADDR,
|
||
/*highaddr*/BUS_SPACE_MAXADDR,
|
||
/*filter*/NULL,
|
||
/*filterarg*/NULL,
|
||
/*maxsize*/MAXBSIZE,
|
||
/*nsegments*/ARCMSR_MAX_SG_ENTRIES,
|
||
/*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
|
||
/*flags*/BUS_DMA_ALLOCNOW,
|
||
&pACB->buffer_dmat) != 0)
|
||
#endif
|
||
{
|
||
bus_dma_tag_destroy(pACB->parent_dmat);
|
||
printf("arcmsr_initialize: bus_dma_tag_create ............................failure!\n");
|
||
return ENOMEM;
|
||
}
|
||
/* DMA tag for our srb structures.... Allocate the pfreesrb memory */
|
||
#if __FreeBSD_version >= 502010
|
||
if (bus_dma_tag_create( /*parent_dmat*/pACB->parent_dmat,
|
||
/*alignment*/1,
|
||
/*boundary*/0,
|
||
/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
|
||
/*highaddr*/BUS_SPACE_MAXADDR,
|
||
/*filter*/NULL,
|
||
/*filterarg*/NULL,
|
||
/*maxsize*/((sizeof(struct _SRB) * ARCMSR_MAX_FREESRB_NUM)+0x20),
|
||
/*nsegments*/1,
|
||
/*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
|
||
/*flags*/BUS_DMA_ALLOCNOW,
|
||
/*lockfunc*/NULL,
|
||
/*lockarg*/NULL,
|
||
&pACB->srb_dmat) != 0)
|
||
#else
|
||
if (bus_dma_tag_create( /*parent_dmat*/pACB->parent_dmat,
|
||
/*alignment*/1,
|
||
/*boundary*/0,
|
||
/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
|
||
/*highaddr*/BUS_SPACE_MAXADDR,
|
||
/*filter*/NULL,
|
||
/*filterarg*/NULL,
|
||
/*maxsize*/((sizeof(struct _SRB) * ARCMSR_MAX_FREESRB_NUM)+0x20),
|
||
/*nsegments*/1,
|
||
/*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
|
||
/*flags*/BUS_DMA_ALLOCNOW,
|
||
&pACB->srb_dmat) != 0)
|
||
#endif
|
||
{
|
||
bus_dma_tag_destroy(pACB->buffer_dmat);
|
||
bus_dma_tag_destroy(pACB->parent_dmat);
|
||
printf("arcmsr_initialize: pACB->srb_dmat bus_dma_tag_create .....................failure!\n");
|
||
return ENXIO;
|
||
}
|
||
/* Allocation for our srbs */
|
||
if (bus_dmamem_alloc(pACB->srb_dmat, (void **)&pACB->uncacheptr, BUS_DMA_WAITOK | BUS_DMA_COHERENT, &pACB->srb_dmamap) != 0)
|
||
{
|
||
bus_dma_tag_destroy(pACB->srb_dmat);
|
||
bus_dma_tag_destroy(pACB->buffer_dmat);
|
||
bus_dma_tag_destroy(pACB->parent_dmat);
|
||
printf("arcmsr_initialize: pACB->srb_dmat bus_dma_tag_create ...............failure!\n");
|
||
return ENXIO;
|
||
}
|
||
/* And permanently map them */
|
||
if(bus_dmamap_load(pACB->srb_dmat, pACB->srb_dmamap,pACB->uncacheptr,(sizeof(struct _SRB) * ARCMSR_MAX_FREESRB_NUM)+0x20,arcmsr_map_freesrb, pACB, /*flags*/0))
|
||
{
|
||
bus_dma_tag_destroy(pACB->srb_dmat);
|
||
bus_dma_tag_destroy(pACB->buffer_dmat);
|
||
bus_dma_tag_destroy(pACB->parent_dmat);
|
||
printf("arcmsr_initialize: bus_dmamap_load................... failure!\n");
|
||
return ENXIO;
|
||
}
|
||
pci_command=pci_read_config(dev,PCIR_COMMAND,2);
|
||
pci_command |= PCIM_CMD_BUSMASTEREN;
|
||
pci_command |= PCIM_CMD_PERRESPEN;
|
||
pci_command |= PCIM_CMD_MWRICEN;
|
||
/* Enable Busmaster/Mem */
|
||
pci_command |= PCIM_CMD_MEMEN;
|
||
pci_write_config(dev,PCIR_COMMAND,pci_command,2);
|
||
pACB->sys_res_arcmsr=bus_alloc_resource(dev,SYS_RES_MEMORY,&rid,0,~0,0x1000,RF_ACTIVE);
|
||
if(pACB->sys_res_arcmsr == NULL)
|
||
{
|
||
arcmsr_free_resource(pACB);
|
||
printf("arcmsr_initialize: bus_alloc_resource .....................failure!\n");
|
||
return ENOMEM;
|
||
}
|
||
if(rman_get_start(pACB->sys_res_arcmsr) <= 0)
|
||
{
|
||
arcmsr_free_resource(pACB);
|
||
printf("arcmsr_initialize: rman_get_start ...........................failure!\n");
|
||
return ENXIO;
|
||
}
|
||
mem_base=(vm_offset_t) rman_get_virtual(pACB->sys_res_arcmsr);
|
||
if(mem_base==0)
|
||
{
|
||
arcmsr_free_resource(pACB);
|
||
printf("arcmsr_initialize: rman_get_virtual ..........................failure!\n");
|
||
return ENXIO;
|
||
}
|
||
if(pACB->acb_flags & ACB_F_MAPFREESRB_FAILD)
|
||
{
|
||
arcmsr_free_resource(pACB);
|
||
printf("arcmsr_initialize: arman_get_virtual ..........................failure!\n");
|
||
return ENXIO;
|
||
}
|
||
pACB->btag=rman_get_bustag(pACB->sys_res_arcmsr);
|
||
pACB->bhandle=rman_get_bushandle(pACB->sys_res_arcmsr);
|
||
pACB->pmu=(PMU)mem_base;
|
||
pACB->acb_flags |= (ACB_F_IOCTL_WQBUFFER_CLEARED|ACB_F_IOCTL_RQBUFFER_CLEARED);
|
||
pACB->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
|
||
arcmsr_iop_init(pACB);
|
||
return(0);
|
||
}
|
||
/*
|
||
************************************************************************
|
||
**
|
||
** attach and init a host adapter
|
||
**
|
||
************************************************************************
|
||
*/
|
||
static LONG arcmsr_attach(device_t dev)
|
||
{
|
||
PACB pACB=device_get_softc(dev);
|
||
LONG unit=device_get_unit(dev);
|
||
struct ccb_setasync csa;
|
||
struct cam_devq *devq; /* Device Queue to use for this SIM */
|
||
struct resource *irqres;
|
||
int rid;
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_attach .............................\n" );
|
||
#endif
|
||
|
||
if(arcmsr_initialize(dev))
|
||
{
|
||
printf("arcmsr_attach: arcmsr_initialize failure!\n");
|
||
return ENXIO;
|
||
}
|
||
/* After setting up the adapter,map our interrupt */
|
||
rid=0;
|
||
irqres=bus_alloc_resource(dev,SYS_RES_IRQ,&rid,0,~0,1,RF_SHAREABLE | RF_ACTIVE);
|
||
if(irqres == NULL || bus_setup_intr(dev,irqres,INTR_TYPE_CAM,arcmsr_interrupt,pACB,&pACB->ih))
|
||
{
|
||
arcmsr_free_resource(pACB);
|
||
printf("arcmsr%d: unable to register interrupt handler!\n",unit);
|
||
return ENXIO;
|
||
}
|
||
pACB->irqres=irqres;
|
||
pACB->pci_dev=dev;
|
||
pACB->pci_unit=unit;
|
||
/*
|
||
* Now let the CAM generic SCSI layer find the SCSI devices on
|
||
* the bus * start queue to reset to the idle loop. *
|
||
* Create device queue of SIM(s) * (MAX_START_JOB - 1) :
|
||
* max_sim_transactions
|
||
*/
|
||
devq=cam_simq_alloc(ARCMSR_MAX_START_JOB);
|
||
if(devq == NULL)
|
||
{
|
||
arcmsr_free_resource(pACB);
|
||
bus_release_resource(dev, SYS_RES_IRQ, 0, pACB->irqres);
|
||
printf("arcmsr_attach: cam_simq_alloc failure!\n");
|
||
return ENXIO;
|
||
}
|
||
pACB->psim=cam_sim_alloc(arcmsr_action,arcmsr_poll,"arcmsr",pACB,pACB->pci_unit,1,ARCMSR_MAX_OUTSTANDING_CMD,devq);
|
||
if(pACB->psim == NULL)
|
||
{
|
||
arcmsr_free_resource(pACB);
|
||
bus_release_resource(dev, SYS_RES_IRQ, 0, pACB->irqres);
|
||
cam_simq_free(devq);
|
||
printf("arcmsr_attach: cam_sim_alloc ..................failure!\n");
|
||
return ENXIO;
|
||
}
|
||
if(xpt_bus_register(pACB->psim,0) != CAM_SUCCESS)
|
||
{
|
||
arcmsr_free_resource(pACB);
|
||
bus_release_resource(dev, SYS_RES_IRQ, 0, pACB->irqres);
|
||
cam_sim_free(pACB->psim,/*free_devq*/TRUE);
|
||
printf("arcmsr_attach: xpt_bus_register .......................failure!\n");
|
||
return ENXIO;
|
||
}
|
||
if(xpt_create_path(&pACB->ppath,/* periph */ NULL,cam_sim_path(pACB->psim),CAM_TARGET_WILDCARD,CAM_LUN_WILDCARD) != CAM_REQ_CMP)
|
||
{
|
||
arcmsr_free_resource(pACB);
|
||
bus_release_resource(dev, SYS_RES_IRQ, 0, pACB->irqres);
|
||
xpt_bus_deregister(cam_sim_path(pACB->psim));
|
||
cam_sim_free(pACB->psim,/* free_simq */ TRUE);
|
||
printf("arcmsr_attach: xpt_create_path .....................failure!\n");
|
||
return ENXIO;
|
||
}
|
||
/*
|
||
****************************************************
|
||
*/
|
||
xpt_setup_ccb(&csa.ccb_h,pACB->ppath,/*priority*/5);
|
||
csa.ccb_h.func_code=XPT_SASYNC_CB;
|
||
csa.event_enable=AC_FOUND_DEVICE|AC_LOST_DEVICE;
|
||
csa.callback=arcmsr_async;
|
||
csa.callback_arg=pACB->psim;
|
||
xpt_action((union ccb *)&csa);
|
||
/* Create the control device. */
|
||
pACB->ioctl_dev=make_dev(&arcmsr_cdevsw, unit, UID_ROOT, GID_WHEEL /* GID_OPERATOR */, S_IRUSR | S_IWUSR, "arcmsr%d", unit);
|
||
#if __FreeBSD_version < 503000
|
||
pACB->ioctl_dev->si_drv1=pACB;
|
||
#endif
|
||
#if __FreeBSD_version > 500005
|
||
(void)make_dev_alias(pACB->ioctl_dev, "arc%d", unit);
|
||
#endif
|
||
|
||
#if 0
|
||
#if __FreeBSD_version > 500005
|
||
if(kthread_create(arcmsr_do_thread_works, pACB, &pACB->kthread_proc,0,"arcmsr%d: kthread",pACB->pci_unit))
|
||
{
|
||
device_printf(pACB->pci_dev,"cannot create kernel thread for this host adapetr\n");
|
||
xpt_bus_deregister(cam_sim_path(pACB->psim));
|
||
cam_sim_free(pACB->psim,/* free_simq */ TRUE);
|
||
panic("arcmsr plunge kernel thread fail");
|
||
}
|
||
#else
|
||
if(kthread_create(arcmsr_do_thread_works, pACB, &pACB->kthread_proc,"arcmsr%d: kthread", pACB->pci_unit))
|
||
{
|
||
device_printf(pACB->pci_dev,"cannot create kernel thread for this host adapetr\n");
|
||
xpt_bus_deregister(cam_sim_path(pACB->psim));
|
||
cam_sim_free(pACB->psim,/* free_simq */ TRUE);
|
||
panic("arcmsr plunge kernel thread fail");
|
||
}
|
||
#endif
|
||
#endif
|
||
return 0;
|
||
}
|
||
/*
|
||
************************************************************************
|
||
**
|
||
**
|
||
**
|
||
************************************************************************
|
||
*/
|
||
static LONG arcmsr_probe(device_t dev)
|
||
{
|
||
ULONG id;
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_probe................. \n");
|
||
#endif
|
||
switch(id=pci_get_devid(dev))
|
||
{
|
||
case PCIDevVenIDARC1110:
|
||
device_set_desc(dev,"ARECA ARC1110 PCI-X 4 PORTS SATA RAID CONTROLLER \n" ARCMSR_DRIVER_VERSION );
|
||
return 0;
|
||
case PCIDevVenIDARC1120:
|
||
device_set_desc(dev,"ARECA ARC1120 PCI-X 8 PORTS SATA RAID CONTROLLER (RAID6-ENGINE Inside) \n" ARCMSR_DRIVER_VERSION);
|
||
return 0;
|
||
case PCIDevVenIDARC1130:
|
||
device_set_desc(dev,"ARECA ARC1130 PCI-X 12 PORTS SATA RAID CONTROLLER (RAID6-ENGINE Inside) \n" ARCMSR_DRIVER_VERSION);
|
||
return 0;
|
||
case PCIDevVenIDARC1160:
|
||
device_set_desc(dev,"ARECA ARC1160 PCI-X 16 PORTS SATA RAID CONTROLLER (RAID6-ENGINE Inside) \n" ARCMSR_DRIVER_VERSION);
|
||
return 0;
|
||
case PCIDevVenIDARC1210:
|
||
device_set_desc(dev,"ARECA ARC1210 PCI-EXPRESS 4 PORTS SATA RAID CONTROLLER \n" ARCMSR_DRIVER_VERSION);
|
||
return 0;
|
||
case PCIDevVenIDARC1220:
|
||
device_set_desc(dev,"ARECA ARC1220 PCI-EXPRESS 8 PORTS SATA RAID CONTROLLER (RAID6-ENGINE Inside) \n" ARCMSR_DRIVER_VERSION);
|
||
return 0;
|
||
case PCIDevVenIDARC1230:
|
||
device_set_desc(dev,"ARECA ARC1230 PCI-EXPRESS 12 PORTS SATA RAID CONTROLLER (RAID6-ENGINE Inside) \n" ARCMSR_DRIVER_VERSION);
|
||
return 0;
|
||
case PCIDevVenIDARC1260:
|
||
device_set_desc(dev,"ARECA ARC1260 PCI-EXPRESS 16 PORTS SATA RAID CONTROLLER (RAID6-ENGINE Inside) \n" ARCMSR_DRIVER_VERSION);
|
||
return 0;
|
||
}
|
||
return ENXIO;
|
||
}
|
||
/*
|
||
************************************************************************
|
||
**
|
||
**
|
||
**
|
||
************************************************************************
|
||
*/
|
||
static VOID arcmsr_shutdown(device_t dev)
|
||
{
|
||
LONG i,abort_cmd_cnt=0;
|
||
ULONG s,intmask_org;
|
||
PSRB pSRB;
|
||
PACB pACB=device_get_softc(dev);
|
||
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_shutdown................. \n");
|
||
#endif
|
||
s=splcam();
|
||
/* disable all outbound interrupt */
|
||
intmask_org=CHIP_REG_READ32(&pACB->pmu->outbound_intmask);
|
||
CHIP_REG_WRITE32(&pACB->pmu->outbound_intmask,(intmask_org|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE));
|
||
/* stop adapter background rebuild */
|
||
arcmsr_stop_adapter_bgrb(pACB);
|
||
if(arcmsr_wait_msgint_ready(pACB)!=TRUE)
|
||
{
|
||
printf("arcmsr_pcidev_disattach: wait 'stop adapter rebulid' timeout.... \n");
|
||
}
|
||
arcmsr_flush_adapter_cache(pACB);
|
||
if(arcmsr_wait_msgint_ready(pACB)!=TRUE)
|
||
{
|
||
printf("arcmsr_pcidev_disattach: wait 'flush adapter cache' timeout.... \n");
|
||
}
|
||
/* abort all outstanding command */
|
||
pACB->acb_flags |= ACB_F_SCSISTOPADAPTER;
|
||
pACB->acb_flags &= ~ACB_F_IOP_INITED;
|
||
if(pACB->srboutstandingcount!=0)
|
||
{
|
||
PSRB pfreesrb;
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_pcidev_disattach: .....pACB->srboutstandingcount!=0 \n");
|
||
#endif
|
||
/* Q back all outstanding srb into wait exec psrb Q*/
|
||
pfreesrb=pACB->pfreesrb;
|
||
for(i=0;i<ARCMSR_MAX_FREESRB_NUM;i++)
|
||
{
|
||
pSRB=&pfreesrb[i];
|
||
if(pSRB->startdone==ARCMSR_SRB_START)
|
||
{
|
||
pSRB->srb_flags|=SRB_FLAG_MASTER_ABORTED;
|
||
pSRB->pccb->ccb_h.status=CAM_REQ_ABORTED;
|
||
abort_cmd_cnt++;
|
||
}
|
||
}
|
||
if(abort_cmd_cnt!=0)
|
||
{
|
||
#if ARCMSR_DEBUG0
|
||
printf("arcmsr_pcidev_disattach: .....abort_cmd_cnt!=0 \n");
|
||
#endif
|
||
arcmsr_abort_allcmd(pACB);
|
||
if(arcmsr_wait_msgint_ready(pACB)!=TRUE)
|
||
{
|
||
printf("arcmsr_pcidev_disattach: wait 'abort all outstanding command' timeout.................in \n");
|
||
}
|
||
}
|
||
atomic_set_int(&pACB->srboutstandingcount,0);
|
||
}
|
||
if(pACB->srbwait2gocount!=0)
|
||
{ /*remove first wait2go srb and abort it*/
|
||
for(i=0;i<ARCMSR_MAX_OUTSTANDING_CMD;i++)
|
||
{
|
||
pSRB=pACB->psrbwait2go[i];
|
||
if(pSRB!=NULL)
|
||
{
|
||
pACB->psrbwait2go[i]=NULL;
|
||
atomic_subtract_int(&pACB->srbwait2gocount,1);
|
||
pSRB->pccb->ccb_h.status=CAM_REQ_ABORTED;
|
||
arcmsr_srb_complete(pSRB);
|
||
}
|
||
}
|
||
}
|
||
splx(s);
|
||
pACB->acb_flags |= ACB_F_STOP_THREAD;
|
||
wakeup(pACB->kthread_proc);/* signal to kernel thread do_dpcQ: "stop thread" */
|
||
return;
|
||
}
|
||
/*
|
||
************************************************************************
|
||
**
|
||
**
|
||
**
|
||
************************************************************************
|
||
*/
|
||
static LONG arcmsr_detach(device_t dev)
|
||
{
|
||
PACB pACB=device_get_softc(dev);
|
||
|
||
arcmsr_shutdown(dev);
|
||
arcmsr_free_resource(pACB);
|
||
bus_release_resource(dev, SYS_RES_MEMORY, PCIR_MAPS, pACB->sys_res_arcmsr);
|
||
bus_teardown_intr(dev, pACB->irqres, pACB->ih);
|
||
bus_release_resource(dev, SYS_RES_IRQ, 0, pACB->irqres);
|
||
xpt_async(AC_LOST_DEVICE, pACB->ppath, NULL);
|
||
xpt_free_path(pACB->ppath);
|
||
xpt_bus_deregister(cam_sim_path(pACB->psim));
|
||
cam_sim_free(pACB->psim, TRUE);
|
||
return (0);
|
||
}
|
||
|
||
|
||
|