1f1c579b1SScott Long /* 246a7789eSMatt Jacob ***************************************************************************************** 3f1c579b1SScott Long ** O.S : FreeBSD 4f1c579b1SScott Long ** FILE NAME : arcmsr.c 5f1c579b1SScott Long ** BY : Erich Chen 6f1c579b1SScott Long ** Description: SCSI RAID Device Driver for 7ad6d6297SScott Long ** ARECA (ARC11XX/ARC12XX/ARC13XX/ARC16XX) SATA/SAS RAID HOST Adapter 8ad6d6297SScott Long ** ARCMSR RAID Host adapter 9ad6d6297SScott Long ** [RAID controller:INTEL 331(PCI-X) 341(PCI-EXPRESS) chip set] 10f1c579b1SScott Long ****************************************************************************************** 11f1c579b1SScott Long ************************************************************************ 12f1c579b1SScott Long ** 13f1c579b1SScott Long ** Copyright (c) 2004-2006 ARECA Co. Ltd. 14f1c579b1SScott Long ** Erich Chen, Taipei Taiwan All rights reserved. 15f1c579b1SScott Long ** 16f1c579b1SScott Long ** Redistribution and use in source and binary forms, with or without 17f1c579b1SScott Long ** modification, are permitted provided that the following conditions 18f1c579b1SScott Long ** are met: 19f1c579b1SScott Long ** 1. Redistributions of source code must retain the above copyright 20f1c579b1SScott Long ** notice, this list of conditions and the following disclaimer. 21f1c579b1SScott Long ** 2. Redistributions in binary form must reproduce the above copyright 22f1c579b1SScott Long ** notice, this list of conditions and the following disclaimer in the 23f1c579b1SScott Long ** documentation and/or other materials provided with the distribution. 24f1c579b1SScott Long ** 3. The name of the author may not be used to endorse or promote products 25f1c579b1SScott Long ** derived from this software without specific prior written permission. 26f1c579b1SScott Long ** 27f1c579b1SScott Long ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 28f1c579b1SScott Long ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 29f1c579b1SScott Long ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 30f1c579b1SScott Long ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 31f1c579b1SScott Long ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT 32f1c579b1SScott Long ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33f1c579b1SScott Long ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY 34f1c579b1SScott Long ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35f1c579b1SScott Long **(INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF 36f1c579b1SScott Long ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37f1c579b1SScott Long ************************************************************************** 38f1c579b1SScott Long ** History 39f1c579b1SScott Long ** 40f1c579b1SScott Long ** REV# DATE NAME DESCRIPTION 41f1c579b1SScott Long ** 1.00.00.00 3/31/2004 Erich Chen First release 42f1c579b1SScott Long ** 1.20.00.02 11/29/2004 Erich Chen bug fix with arcmsr_bus_reset when PHY error 43ad6d6297SScott Long ** 1.20.00.03 4/19/2005 Erich Chen add SATA 24 Ports adapter type support 44ad6d6297SScott Long ** clean unused function 45ad6d6297SScott Long ** 1.20.00.12 9/12/2005 Erich Chen bug fix with abort command handling, 46ad6d6297SScott Long ** firmware version check 47ad6d6297SScott Long ** and firmware update notify for hardware bug fix 48ad6d6297SScott Long ** handling if none zero high part physical address 49ad6d6297SScott Long ** of srb resource 50ad6d6297SScott Long ** 1.20.00.13 8/18/2006 Erich Chen remove pending srb and report busy 51ad6d6297SScott Long ** add iop message xfer 52ad6d6297SScott Long ** with scsi pass-through command 53ad6d6297SScott Long ** add new device id of sas raid adapters 54ad6d6297SScott Long ** code fit for SPARC64 & PPC 55f48f00a1SScott Long ** 1.20.00.14 02/05/2007 Erich Chen bug fix for incorrect ccb_h.status report 56f48f00a1SScott Long ** and cause g_vfs_done() read write error 5744f05562SScott Long ** 1.20.00.15 10/10/2007 Erich Chen support new RAID adapter type ARC120x 58641182baSXin LI ** 1.20.00.16 10/10/2009 Erich Chen Bug fix for RAID adapter type ARC120x 59641182baSXin LI ** bus_dmamem_alloc() with BUS_DMA_ZERO 60f1c579b1SScott Long ****************************************************************************************** 61ad6d6297SScott Long * $FreeBSD$ 62f1c579b1SScott Long */ 63f1c579b1SScott Long #include <sys/param.h> 64f1c579b1SScott Long #include <sys/systm.h> 65f1c579b1SScott Long #include <sys/malloc.h> 66f1c579b1SScott Long #include <sys/kernel.h> 67f1c579b1SScott Long #include <sys/bus.h> 68f1c579b1SScott Long #include <sys/queue.h> 69f1c579b1SScott Long #include <sys/stat.h> 70f1c579b1SScott Long #include <sys/devicestat.h> 71f1c579b1SScott Long #include <sys/kthread.h> 72f1c579b1SScott Long #include <sys/module.h> 73f1c579b1SScott Long #include <sys/proc.h> 74f1c579b1SScott Long #include <sys/lock.h> 75f1c579b1SScott Long #include <sys/sysctl.h> 76f1c579b1SScott Long #include <sys/poll.h> 77f1c579b1SScott Long #include <sys/ioccom.h> 78f1c579b1SScott Long #include <vm/vm.h> 79f1c579b1SScott Long #include <vm/vm_param.h> 80f1c579b1SScott Long #include <vm/pmap.h> 81f1c579b1SScott Long 82f1c579b1SScott Long #include <isa/rtc.h> 83f1c579b1SScott Long 84f1c579b1SScott Long #include <machine/bus.h> 85f1c579b1SScott Long #include <machine/resource.h> 86f1c579b1SScott Long #include <machine/atomic.h> 87f1c579b1SScott Long #include <sys/conf.h> 88f1c579b1SScott Long #include <sys/rman.h> 89f1c579b1SScott Long 90f1c579b1SScott Long #include <cam/cam.h> 91f1c579b1SScott Long #include <cam/cam_ccb.h> 92f1c579b1SScott Long #include <cam/cam_sim.h> 93f1c579b1SScott Long #include <cam/cam_xpt_sim.h> 94f1c579b1SScott Long #include <cam/cam_debug.h> 95f1c579b1SScott Long #include <cam/scsi/scsi_all.h> 96f1c579b1SScott Long #include <cam/scsi/scsi_message.h> 97f1c579b1SScott Long /* 98f1c579b1SScott Long ************************************************************************** 99f1c579b1SScott Long ************************************************************************** 100f1c579b1SScott Long */ 101f1c579b1SScott Long #if __FreeBSD_version >= 500005 102f1c579b1SScott Long #include <sys/selinfo.h> 103f1c579b1SScott Long #include <sys/mutex.h> 104ad6d6297SScott Long #include <sys/endian.h> 105f1c579b1SScott Long #include <dev/pci/pcivar.h> 106f1c579b1SScott Long #include <dev/pci/pcireg.h> 107579ec1a5SScott Long #define ARCMSR_LOCK_INIT(l, s) mtx_init(l, s, NULL, MTX_DEF) 1085878cbecSScott Long #define ARCMSR_LOCK_DESTROY(l) mtx_destroy(l) 109f1c579b1SScott Long #define ARCMSR_LOCK_ACQUIRE(l) mtx_lock(l) 110f1c579b1SScott Long #define ARCMSR_LOCK_RELEASE(l) mtx_unlock(l) 111ad6d6297SScott Long #define ARCMSR_LOCK_TRY(l) mtx_trylock(l) 112ad6d6297SScott Long #define arcmsr_htole32(x) htole32(x) 113f1c579b1SScott Long typedef struct mtx arcmsr_lock_t; 114f1c579b1SScott Long #else 115f1c579b1SScott Long #include <sys/select.h> 116f1c579b1SScott Long #include <pci/pcivar.h> 117f1c579b1SScott Long #include <pci/pcireg.h> 118f1c579b1SScott Long #define ARCMSR_LOCK_INIT(l, s) simple_lock_init(l) 1195878cbecSScott Long #define ARCMSR_LOCK_DESTROY(l) 120f1c579b1SScott Long #define ARCMSR_LOCK_ACQUIRE(l) simple_lock(l) 121f1c579b1SScott Long #define ARCMSR_LOCK_RELEASE(l) simple_unlock(l) 122ad6d6297SScott Long #define ARCMSR_LOCK_TRY(l) simple_lock_try(l) 123ad6d6297SScott Long #define arcmsr_htole32(x) (x) 124f1c579b1SScott Long typedef struct simplelock arcmsr_lock_t; 125f1c579b1SScott Long #endif 12644f05562SScott Long 12744f05562SScott Long #if !defined(CAM_NEW_TRAN_CODE) && __FreeBSD_version >= 700025 12844f05562SScott Long #define CAM_NEW_TRAN_CODE 1 12944f05562SScott Long #endif 13044f05562SScott Long 131f1c579b1SScott Long #include <dev/arcmsr/arcmsr.h> 13244f05562SScott Long #define ARCMSR_SRBS_POOL_SIZE ((sizeof(struct CommandControlBlock) * ARCMSR_MAX_FREESRB_NUM)) 133f1c579b1SScott Long /* 134f1c579b1SScott Long ************************************************************************** 135f1c579b1SScott Long ************************************************************************** 136f1c579b1SScott Long */ 13744f05562SScott Long #define CHIP_REG_READ32(s, b, r) bus_space_read_4(acb->btag[b], acb->bhandle[b], offsetof(struct s, r)) 13844f05562SScott Long #define CHIP_REG_WRITE32(s, b, r, d) bus_space_write_4(acb->btag[b], acb->bhandle[b], offsetof(struct s, r), d) 139f1c579b1SScott Long /* 140f1c579b1SScott Long ************************************************************************** 141f1c579b1SScott Long ************************************************************************** 142f1c579b1SScott Long */ 143ad6d6297SScott Long static struct CommandControlBlock * arcmsr_get_freesrb(struct AdapterControlBlock *acb); 144ad6d6297SScott Long static u_int8_t arcmsr_seek_cmd2abort(union ccb * abortccb); 145f2aa0e9fSWarner Losh static int arcmsr_probe(device_t dev); 146f2aa0e9fSWarner Losh static int arcmsr_attach(device_t dev); 147f2aa0e9fSWarner Losh static int arcmsr_detach(device_t dev); 148ad6d6297SScott Long static u_int32_t arcmsr_iop_ioctlcmd(struct AdapterControlBlock *acb, u_int32_t ioctl_cmd, caddr_t arg); 149ad6d6297SScott Long static void arcmsr_iop_parking(struct AdapterControlBlock *acb); 150f2aa0e9fSWarner Losh static int arcmsr_shutdown(device_t dev); 15144f05562SScott Long static void arcmsr_interrupt(struct AdapterControlBlock *acb); 152ad6d6297SScott Long static void arcmsr_polling_srbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_srb); 153ad6d6297SScott Long static void arcmsr_free_resource(struct AdapterControlBlock *acb); 154ad6d6297SScott Long static void arcmsr_bus_reset(struct AdapterControlBlock *acb); 155ad6d6297SScott Long static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb); 156ad6d6297SScott Long static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb); 157ad6d6297SScott Long static void arcmsr_iop_init(struct AdapterControlBlock *acb); 158ad6d6297SScott Long static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb); 15944f05562SScott Long static void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb); 160ad6d6297SScott Long static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb); 161ad6d6297SScott Long static void arcmsr_srb_complete(struct CommandControlBlock *srb, int stand_flag); 162ad6d6297SScott Long static void arcmsr_iop_reset(struct AdapterControlBlock *acb); 163ad6d6297SScott Long static void arcmsr_report_sense_info(struct CommandControlBlock *srb); 164ad6d6297SScott Long static void arcmsr_build_srb(struct CommandControlBlock *srb, bus_dma_segment_t * dm_segs, u_int32_t nseg); 165ad6d6297SScott Long static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, union ccb * pccb); 166ad6d6297SScott Long static int arcmsr_resume(device_t dev); 167ad6d6297SScott Long static int arcmsr_suspend(device_t dev); 168f1c579b1SScott Long /* 169f1c579b1SScott Long ************************************************************************** 170ad6d6297SScott Long ************************************************************************** 171ad6d6297SScott Long */ 172ad6d6297SScott Long static void UDELAY(u_int32_t us) { DELAY(us); } 173ad6d6297SScott Long /* 174ad6d6297SScott Long ************************************************************************** 175f1c579b1SScott Long ************************************************************************** 176f1c579b1SScott Long */ 177f1c579b1SScott Long static bus_dmamap_callback_t arcmsr_map_freesrb; 178f1c579b1SScott Long static bus_dmamap_callback_t arcmsr_executesrb; 179f1c579b1SScott Long /* 180f1c579b1SScott Long ************************************************************************** 181f1c579b1SScott Long ************************************************************************** 182f1c579b1SScott Long */ 183f1c579b1SScott Long static d_open_t arcmsr_open; 184f1c579b1SScott Long static d_close_t arcmsr_close; 185f1c579b1SScott Long static d_ioctl_t arcmsr_ioctl; 186f1c579b1SScott Long 187f1c579b1SScott Long static device_method_t arcmsr_methods[]={ 188f1c579b1SScott Long DEVMETHOD(device_probe, arcmsr_probe), 189f1c579b1SScott Long DEVMETHOD(device_attach, arcmsr_attach), 190f1c579b1SScott Long DEVMETHOD(device_detach, arcmsr_detach), 191f1c579b1SScott Long DEVMETHOD(device_shutdown, arcmsr_shutdown), 192ad6d6297SScott Long DEVMETHOD(device_suspend, arcmsr_suspend), 193ad6d6297SScott Long DEVMETHOD(device_resume, arcmsr_resume), 194ad6d6297SScott Long 195ad6d6297SScott Long DEVMETHOD(bus_print_child, bus_generic_print_child), 196ad6d6297SScott Long DEVMETHOD(bus_driver_added, bus_generic_driver_added), 197f1c579b1SScott Long { 0, 0 } 198f1c579b1SScott Long }; 199f1c579b1SScott Long 200f1c579b1SScott Long static driver_t arcmsr_driver={ 201ad6d6297SScott Long "arcmsr", arcmsr_methods, sizeof(struct AdapterControlBlock) 202f1c579b1SScott Long }; 203f1c579b1SScott Long 204f1c579b1SScott Long static devclass_t arcmsr_devclass; 205f1c579b1SScott Long DRIVER_MODULE(arcmsr, pci, arcmsr_driver, arcmsr_devclass, 0, 0); 206d3cf342dSScott Long MODULE_DEPEND(arcmsr, pci, 1, 1, 1); 207d3cf342dSScott Long MODULE_DEPEND(arcmsr, cam, 1, 1, 1); 208ad6d6297SScott Long #ifndef BUS_DMA_COHERENT 209ad6d6297SScott Long #define BUS_DMA_COHERENT 0x04 /* hint: map memory in a coherent way */ 210ad6d6297SScott Long #endif 211ad6d6297SScott Long #if __FreeBSD_version >= 501000 212ad6d6297SScott Long #ifndef D_NEEDGIANT 213ad6d6297SScott Long #define D_NEEDGIANT 0x00400000 /* driver want Giant */ 214ad6d6297SScott Long #endif 215ad6d6297SScott Long #ifndef D_VERSION 216ad6d6297SScott Long #define D_VERSION 0x20011966 217ad6d6297SScott Long #endif 218f1c579b1SScott Long static struct cdevsw arcmsr_cdevsw={ 219ad6d6297SScott Long #if __FreeBSD_version > 502010 220f1c579b1SScott Long .d_version = D_VERSION, 221ad6d6297SScott Long #endif 222f1c579b1SScott Long .d_flags = D_NEEDGIANT, 223f1c579b1SScott Long .d_open = arcmsr_open, /* open */ 224f1c579b1SScott Long .d_close = arcmsr_close, /* close */ 225f1c579b1SScott Long .d_ioctl = arcmsr_ioctl, /* ioctl */ 226f1c579b1SScott Long .d_name = "arcmsr", /* name */ 227f1c579b1SScott Long }; 228f1c579b1SScott Long #else 229f1c579b1SScott Long #define ARCMSR_CDEV_MAJOR 180 230f1c579b1SScott Long 231f1c579b1SScott Long static struct cdevsw arcmsr_cdevsw = { 232f1c579b1SScott Long arcmsr_open, /* open */ 233f1c579b1SScott Long arcmsr_close, /* close */ 234f1c579b1SScott Long noread, /* read */ 235f1c579b1SScott Long nowrite, /* write */ 236f1c579b1SScott Long arcmsr_ioctl, /* ioctl */ 237f1c579b1SScott Long nopoll, /* poll */ 238f1c579b1SScott Long nommap, /* mmap */ 239f1c579b1SScott Long nostrategy, /* strategy */ 240f1c579b1SScott Long "arcmsr", /* name */ 241f1c579b1SScott Long ARCMSR_CDEV_MAJOR, /* major */ 242f1c579b1SScott Long nodump, /* dump */ 243f1c579b1SScott Long nopsize, /* psize */ 244f1c579b1SScott Long 0 /* flags */ 245f1c579b1SScott Long }; 246f1c579b1SScott Long #endif 247f1c579b1SScott Long 248f1c579b1SScott Long #if __FreeBSD_version < 500005 249f1c579b1SScott Long static int arcmsr_open(dev_t dev, int flags, int fmt, struct proc *proc) 250f1c579b1SScott Long #else 251f1c579b1SScott Long #if __FreeBSD_version < 503000 252f1c579b1SScott Long static int arcmsr_open(dev_t dev, int flags, int fmt, struct thread *proc) 253f1c579b1SScott Long #else 25400b4e54aSWarner Losh static int arcmsr_open(struct cdev *dev, int flags, int fmt, struct thread *proc) 255f1c579b1SScott Long #endif 256f1c579b1SScott Long #endif 257f1c579b1SScott Long { 258f1c579b1SScott Long #if __FreeBSD_version < 503000 259ad6d6297SScott Long struct AdapterControlBlock *acb=dev->si_drv1; 260f1c579b1SScott Long #else 2616bfa9a2dSEd Schouten int unit = dev2unit(dev); 262ad6d6297SScott Long struct AdapterControlBlock *acb = devclass_get_softc(arcmsr_devclass, unit); 263f1c579b1SScott Long #endif 264ad6d6297SScott Long if(acb==NULL) { 265f1c579b1SScott Long return ENXIO; 266f1c579b1SScott Long } 267f1c579b1SScott Long return 0; 268f1c579b1SScott Long } 269f1c579b1SScott Long /* 270f1c579b1SScott Long ************************************************************************** 271f1c579b1SScott Long ************************************************************************** 272f1c579b1SScott Long */ 273f1c579b1SScott Long #if __FreeBSD_version < 500005 274f1c579b1SScott Long static int arcmsr_close(dev_t dev, int flags, int fmt, struct proc *proc) 275f1c579b1SScott Long #else 276f1c579b1SScott Long #if __FreeBSD_version < 503000 277f1c579b1SScott Long static int arcmsr_close(dev_t dev, int flags, int fmt, struct thread *proc) 278f1c579b1SScott Long #else 27900b4e54aSWarner Losh static int arcmsr_close(struct cdev *dev, int flags, int fmt, struct thread *proc) 280f1c579b1SScott Long #endif 281f1c579b1SScott Long #endif 282f1c579b1SScott Long { 283f1c579b1SScott Long #if __FreeBSD_version < 503000 284ad6d6297SScott Long struct AdapterControlBlock *acb=dev->si_drv1; 285f1c579b1SScott Long #else 2866bfa9a2dSEd Schouten int unit = dev2unit(dev); 287ad6d6297SScott Long struct AdapterControlBlock *acb = devclass_get_softc(arcmsr_devclass, unit); 288f1c579b1SScott Long #endif 289ad6d6297SScott Long if(acb==NULL) { 290f1c579b1SScott Long return ENXIO; 291f1c579b1SScott Long } 292f1c579b1SScott Long return 0; 293f1c579b1SScott Long } 294f1c579b1SScott Long /* 295f1c579b1SScott Long ************************************************************************** 296f1c579b1SScott Long ************************************************************************** 297f1c579b1SScott Long */ 298f1c579b1SScott Long #if __FreeBSD_version < 500005 299f1c579b1SScott Long static int arcmsr_ioctl(dev_t dev, u_long ioctl_cmd, caddr_t arg, int flags, struct proc *proc) 300f1c579b1SScott Long #else 301f1c579b1SScott Long #if __FreeBSD_version < 503000 302f1c579b1SScott Long static int arcmsr_ioctl(dev_t dev, u_long ioctl_cmd, caddr_t arg, int flags, struct thread *proc) 303f1c579b1SScott Long #else 30400b4e54aSWarner Losh static int arcmsr_ioctl(struct cdev *dev, u_long ioctl_cmd, caddr_t arg, int flags, struct thread *proc) 305f1c579b1SScott Long #endif 306f1c579b1SScott Long #endif 307f1c579b1SScott Long { 308f1c579b1SScott Long #if __FreeBSD_version < 503000 309ad6d6297SScott Long struct AdapterControlBlock *acb=dev->si_drv1; 310f1c579b1SScott Long #else 3116bfa9a2dSEd Schouten int unit = dev2unit(dev); 312ad6d6297SScott Long struct AdapterControlBlock *acb = devclass_get_softc(arcmsr_devclass, unit); 313f1c579b1SScott Long #endif 314f1c579b1SScott Long 315ad6d6297SScott Long if(acb==NULL) { 316f1c579b1SScott Long return ENXIO; 317f1c579b1SScott Long } 318ad6d6297SScott Long return(arcmsr_iop_ioctlcmd(acb, ioctl_cmd, arg)); 319f1c579b1SScott Long } 320f1c579b1SScott Long /* 32144f05562SScott Long ********************************************************************** 32244f05562SScott Long ********************************************************************** 32344f05562SScott Long */ 32444f05562SScott Long static u_int32_t arcmsr_disable_allintr( struct AdapterControlBlock *acb) 32544f05562SScott Long { 32644f05562SScott Long u_int32_t intmask_org=0; 32744f05562SScott Long 32844f05562SScott Long switch (acb->adapter_type) { 32944f05562SScott Long case ACB_ADAPTER_TYPE_A: { 33044f05562SScott Long /* disable all outbound interrupt */ 33144f05562SScott Long intmask_org=CHIP_REG_READ32(HBA_MessageUnit, 33244f05562SScott Long 0, outbound_intmask)|ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE; /* disable outbound message0 int */ 33344f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 33444f05562SScott Long 0, outbound_intmask, intmask_org|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE); 33544f05562SScott Long } 33644f05562SScott Long break; 33744f05562SScott Long case ACB_ADAPTER_TYPE_B: { 33844f05562SScott Long /* disable all outbound interrupt */ 33944f05562SScott Long intmask_org=CHIP_REG_READ32(HBB_DOORBELL, 34044f05562SScott Long 0, iop2drv_doorbell_mask) & (~ARCMSR_IOP2DRV_MESSAGE_CMD_DONE); /* disable outbound message0 int */ 34144f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 34244f05562SScott Long 0, iop2drv_doorbell_mask, 0); /* disable all interrupt */ 34344f05562SScott Long } 34444f05562SScott Long break; 34544f05562SScott Long } 34644f05562SScott Long return(intmask_org); 34744f05562SScott Long } 34844f05562SScott Long /* 34944f05562SScott Long ********************************************************************** 35044f05562SScott Long ********************************************************************** 35144f05562SScott Long */ 35244f05562SScott Long static void arcmsr_enable_allintr( struct AdapterControlBlock *acb, u_int32_t intmask_org) 35344f05562SScott Long { 35444f05562SScott Long u_int32_t mask; 35544f05562SScott Long 35644f05562SScott Long switch (acb->adapter_type) { 35744f05562SScott Long case ACB_ADAPTER_TYPE_A: { 35844f05562SScott Long /* enable outbound Post Queue, outbound doorbell Interrupt */ 35944f05562SScott Long mask=~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE|ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); 36044f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intmask, intmask_org & mask); 36144f05562SScott Long acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff; 36244f05562SScott Long } 36344f05562SScott Long break; 36444f05562SScott Long case ACB_ADAPTER_TYPE_B: { 36544f05562SScott Long /* disable ARCMSR_IOP2DRV_MESSAGE_CMD_DONE */ 36644f05562SScott Long mask=(ARCMSR_IOP2DRV_DATA_WRITE_OK|ARCMSR_IOP2DRV_DATA_READ_OK|ARCMSR_IOP2DRV_CDB_DONE); 36744f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 36844f05562SScott Long 0, iop2drv_doorbell_mask, intmask_org | mask); /*1=interrupt enable, 0=interrupt disable*/ 36944f05562SScott Long acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f; 37044f05562SScott Long } 37144f05562SScott Long break; 37244f05562SScott Long } 37344f05562SScott Long return; 37444f05562SScott Long } 37544f05562SScott Long /* 37644f05562SScott Long ********************************************************************** 37744f05562SScott Long ********************************************************************** 37844f05562SScott Long */ 37944f05562SScott Long static u_int8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb) 38044f05562SScott Long { 38144f05562SScott Long u_int32_t Index; 38244f05562SScott Long u_int8_t Retries=0x00; 38344f05562SScott Long 38444f05562SScott Long do { 38544f05562SScott Long for(Index=0; Index < 100; Index++) { 38644f05562SScott Long if(CHIP_REG_READ32(HBA_MessageUnit, 38744f05562SScott Long 0, outbound_intstatus) & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { 38844f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 38944f05562SScott Long 0, outbound_intstatus, ARCMSR_MU_OUTBOUND_MESSAGE0_INT);/*clear interrupt*/ 39044f05562SScott Long return TRUE; 39144f05562SScott Long } 39244f05562SScott Long UDELAY(10000); 39344f05562SScott Long }/*max 1 seconds*/ 39444f05562SScott Long }while(Retries++ < 20);/*max 20 sec*/ 39544f05562SScott Long return FALSE; 39644f05562SScott Long } 39744f05562SScott Long /* 39844f05562SScott Long ********************************************************************** 39944f05562SScott Long ********************************************************************** 40044f05562SScott Long */ 40144f05562SScott Long static u_int8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) 40244f05562SScott Long { 40344f05562SScott Long u_int32_t Index; 40444f05562SScott Long u_int8_t Retries=0x00; 40544f05562SScott Long 40644f05562SScott Long do { 40744f05562SScott Long for(Index=0; Index < 100; Index++) { 40844f05562SScott Long if(CHIP_REG_READ32(HBB_DOORBELL, 40944f05562SScott Long 0, iop2drv_doorbell) & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { 41044f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 41144f05562SScott Long 0, iop2drv_doorbell, ARCMSR_MESSAGE_INT_CLEAR_PATTERN);/*clear interrupt*/ 41244f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 41344f05562SScott Long 0, drv2iop_doorbell, ARCMSR_DRV2IOP_END_OF_INTERRUPT); 41444f05562SScott Long return TRUE; 41544f05562SScott Long } 41644f05562SScott Long UDELAY(10000); 41744f05562SScott Long }/*max 1 seconds*/ 41844f05562SScott Long }while(Retries++ < 20);/*max 20 sec*/ 41944f05562SScott Long return FALSE; 42044f05562SScott Long } 42144f05562SScott Long /* 42244f05562SScott Long ************************************************************************ 42344f05562SScott Long ************************************************************************ 42444f05562SScott Long */ 42544f05562SScott Long static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb) 42644f05562SScott Long { 42744f05562SScott Long int retry_count=30;/* enlarge wait flush adapter cache time: 10 minute */ 42844f05562SScott Long 42944f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 43044f05562SScott Long 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_FLUSH_CACHE); 43144f05562SScott Long do { 43244f05562SScott Long if(arcmsr_hba_wait_msgint_ready(acb)) { 43344f05562SScott Long break; 43444f05562SScott Long } else { 43544f05562SScott Long retry_count--; 43644f05562SScott Long } 43744f05562SScott Long }while(retry_count!=0); 43844f05562SScott Long return; 43944f05562SScott Long } 44044f05562SScott Long /* 44144f05562SScott Long ************************************************************************ 44244f05562SScott Long ************************************************************************ 44344f05562SScott Long */ 44444f05562SScott Long static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb) 44544f05562SScott Long { 44644f05562SScott Long int retry_count=30;/* enlarge wait flush adapter cache time: 10 minute */ 44744f05562SScott Long 44844f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 44944f05562SScott Long 0, drv2iop_doorbell, ARCMSR_MESSAGE_FLUSH_CACHE); 45044f05562SScott Long do { 45144f05562SScott Long if(arcmsr_hbb_wait_msgint_ready(acb)) { 45244f05562SScott Long break; 45344f05562SScott Long } else { 45444f05562SScott Long retry_count--; 45544f05562SScott Long } 45644f05562SScott Long }while(retry_count!=0); 45744f05562SScott Long return; 45844f05562SScott Long } 45944f05562SScott Long /* 46044f05562SScott Long ************************************************************************ 46144f05562SScott Long ************************************************************************ 46244f05562SScott Long */ 46344f05562SScott Long static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) 46444f05562SScott Long { 46544f05562SScott Long switch (acb->adapter_type) { 46644f05562SScott Long case ACB_ADAPTER_TYPE_A: { 46744f05562SScott Long arcmsr_flush_hba_cache(acb); 46844f05562SScott Long } 46944f05562SScott Long break; 47044f05562SScott Long case ACB_ADAPTER_TYPE_B: { 47144f05562SScott Long arcmsr_flush_hbb_cache(acb); 47244f05562SScott Long } 47344f05562SScott Long break; 47444f05562SScott Long } 47544f05562SScott Long return; 47644f05562SScott Long } 47744f05562SScott Long /* 478ad6d6297SScott Long ******************************************************************************* 479ad6d6297SScott Long ******************************************************************************* 480f1c579b1SScott Long */ 481ad6d6297SScott Long static int arcmsr_suspend(device_t dev) 482f1c579b1SScott Long { 483ad6d6297SScott Long struct AdapterControlBlock *acb = device_get_softc(dev); 484f1c579b1SScott Long 485ad6d6297SScott Long /* disable all outbound interrupt */ 48644f05562SScott Long arcmsr_disable_allintr(acb); 487ad6d6297SScott Long /* flush controller */ 488ad6d6297SScott Long arcmsr_iop_parking(acb); 489ad6d6297SScott Long return(0); 490ad6d6297SScott Long } 491ad6d6297SScott Long /* 492ad6d6297SScott Long ******************************************************************************* 493ad6d6297SScott Long ******************************************************************************* 494ad6d6297SScott Long */ 495ad6d6297SScott Long static int arcmsr_resume(device_t dev) 496ad6d6297SScott Long { 497ad6d6297SScott Long struct AdapterControlBlock *acb = device_get_softc(dev); 498f1c579b1SScott Long 499ad6d6297SScott Long arcmsr_iop_init(acb); 500ad6d6297SScott Long return(0); 501f1c579b1SScott Long } 502f1c579b1SScott Long /* 503f1c579b1SScott Long ********************************************************************************* 504f1c579b1SScott Long ********************************************************************************* 505f1c579b1SScott Long */ 506ad6d6297SScott Long static void arcmsr_async(void *cb_arg, u_int32_t code, struct cam_path *path, void *arg) 507f1c579b1SScott Long { 508ad6d6297SScott Long struct AdapterControlBlock *acb; 509ad6d6297SScott Long u_int8_t target_id, target_lun; 510f1c579b1SScott Long struct cam_sim * sim; 511f1c579b1SScott Long 512f1c579b1SScott Long sim=(struct cam_sim *) cb_arg; 513ad6d6297SScott Long acb =(struct AdapterControlBlock *) cam_sim_softc(sim); 514ad6d6297SScott Long switch (code) { 515f1c579b1SScott Long case AC_LOST_DEVICE: 516f1c579b1SScott Long target_id=xpt_path_target_id(path); 517f1c579b1SScott Long target_lun=xpt_path_lun_id(path); 51844f05562SScott Long if((target_id > ARCMSR_MAX_TARGETID) 51944f05562SScott Long || (target_lun > ARCMSR_MAX_TARGETLUN)) { 520f1c579b1SScott Long break; 521f1c579b1SScott Long } 522ad6d6297SScott Long printf("%s:scsi id%d lun%d device lost \n" 523ad6d6297SScott Long , device_get_name(acb->pci_dev), target_id, target_lun); 524f1c579b1SScott Long break; 525f1c579b1SScott Long default: 526f1c579b1SScott Long break; 527f1c579b1SScott Long } 528f1c579b1SScott Long } 529f1c579b1SScott Long /* 530f1c579b1SScott Long ********************************************************************** 531f1c579b1SScott Long ********************************************************************** 532f1c579b1SScott Long */ 533ad6d6297SScott Long static void arcmsr_srb_complete(struct CommandControlBlock *srb, int stand_flag) 534f1c579b1SScott Long { 535ad6d6297SScott Long struct AdapterControlBlock *acb=srb->acb; 536ad6d6297SScott Long union ccb * pccb=srb->pccb; 537f1c579b1SScott Long 538ad6d6297SScott Long if((pccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 539f1c579b1SScott Long bus_dmasync_op_t op; 540f1c579b1SScott Long 541ad6d6297SScott Long if((pccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 542f1c579b1SScott Long op = BUS_DMASYNC_POSTREAD; 543ad6d6297SScott Long } else { 544f1c579b1SScott Long op = BUS_DMASYNC_POSTWRITE; 545f1c579b1SScott Long } 546ad6d6297SScott Long bus_dmamap_sync(acb->dm_segs_dmat, srb->dm_segs_dmamap, op); 547ad6d6297SScott Long bus_dmamap_unload(acb->dm_segs_dmat, srb->dm_segs_dmamap); 548f1c579b1SScott Long } 549ad6d6297SScott Long if(stand_flag==1) { 550ad6d6297SScott Long atomic_subtract_int(&acb->srboutstandingcount, 1); 551dc3a205bSScott Long if((acb->acb_flags & ACB_F_CAM_DEV_QFRZN) && ( 552dc3a205bSScott Long acb->srboutstandingcount < ARCMSR_RELEASE_SIMQ_LEVEL)) { 553dc3a205bSScott Long acb->acb_flags &= ~ACB_F_CAM_DEV_QFRZN; 554dc3a205bSScott Long pccb->ccb_h.status |= CAM_RELEASE_SIMQ; 555dc3a205bSScott Long } 556ad6d6297SScott Long } 557ad6d6297SScott Long srb->startdone=ARCMSR_SRB_DONE; 558ad6d6297SScott Long srb->srb_flags=0; 559ad6d6297SScott Long acb->srbworkingQ[acb->workingsrb_doneindex]=srb; 560ad6d6297SScott Long acb->workingsrb_doneindex++; 561ad6d6297SScott Long acb->workingsrb_doneindex %= ARCMSR_MAX_FREESRB_NUM; 562f1c579b1SScott Long xpt_done(pccb); 563f1c579b1SScott Long return; 564f1c579b1SScott Long } 565f1c579b1SScott Long /* 566f1c579b1SScott Long ********************************************************************** 567f1c579b1SScott Long ********************************************************************** 568f1c579b1SScott Long */ 569ad6d6297SScott Long static void arcmsr_report_sense_info(struct CommandControlBlock *srb) 570f1c579b1SScott Long { 571ad6d6297SScott Long union ccb * pccb=srb->pccb; 572f1c579b1SScott Long 573ad6d6297SScott Long pccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 574ad6d6297SScott Long pccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 575ad6d6297SScott Long if(&pccb->csio.sense_data) { 576ad6d6297SScott Long memset(&pccb->csio.sense_data, 0, sizeof(pccb->csio.sense_data)); 577ad6d6297SScott Long memcpy(&pccb->csio.sense_data, srb->arcmsr_cdb.SenseData, 578ad6d6297SScott Long get_min(sizeof(struct SENSE_DATA), sizeof(pccb->csio.sense_data))); 579ad6d6297SScott Long ((u_int8_t *)&pccb->csio.sense_data)[0] = (0x1 << 7 | 0x70); /* Valid,ErrorCode */ 580f1c579b1SScott Long pccb->ccb_h.status |= CAM_AUTOSNS_VALID; 581f1c579b1SScott Long } 582f1c579b1SScott Long return; 583f1c579b1SScott Long } 584f1c579b1SScott Long /* 585f1c579b1SScott Long ********************************************************************* 58644f05562SScott Long ********************************************************************* 58744f05562SScott Long */ 58844f05562SScott Long static void arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb) 58944f05562SScott Long { 59044f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_ABORT_CMD); 59144f05562SScott Long if(!arcmsr_hba_wait_msgint_ready(acb)) { 59244f05562SScott Long printf("arcmsr%d: wait 'abort all outstanding command' timeout \n" 59344f05562SScott Long , acb->pci_unit); 59444f05562SScott Long } 59544f05562SScott Long return; 59644f05562SScott Long } 59744f05562SScott Long /* 59844f05562SScott Long ********************************************************************* 59944f05562SScott Long ********************************************************************* 60044f05562SScott Long */ 60144f05562SScott Long static void arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb) 60244f05562SScott Long { 60344f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_MESSAGE_ABORT_CMD); 60444f05562SScott Long if(!arcmsr_hbb_wait_msgint_ready(acb)) { 60544f05562SScott Long printf("arcmsr%d: wait 'abort all outstanding command' timeout \n" 60644f05562SScott Long , acb->pci_unit); 60744f05562SScott Long } 60844f05562SScott Long return; 60944f05562SScott Long } 61044f05562SScott Long /* 61144f05562SScott Long ********************************************************************* 612f1c579b1SScott Long ********************************************************************* 613f1c579b1SScott Long */ 614ad6d6297SScott Long static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb) 615f1c579b1SScott Long { 61644f05562SScott Long switch (acb->adapter_type) { 61744f05562SScott Long case ACB_ADAPTER_TYPE_A: { 61844f05562SScott Long arcmsr_abort_hba_allcmd(acb); 61944f05562SScott Long } 62044f05562SScott Long break; 62144f05562SScott Long case ACB_ADAPTER_TYPE_B: { 62244f05562SScott Long arcmsr_abort_hbb_allcmd(acb); 62344f05562SScott Long } 62444f05562SScott Long break; 62544f05562SScott Long } 62644f05562SScott Long return; 62744f05562SScott Long } 62844f05562SScott Long /* 62944f05562SScott Long ************************************************************************** 63044f05562SScott Long ************************************************************************** 63144f05562SScott Long */ 63244f05562SScott Long static void arcmsr_report_srb_state(struct AdapterControlBlock *acb, 63344f05562SScott Long struct CommandControlBlock *srb, u_int32_t flag_srb) 63444f05562SScott Long { 63544f05562SScott Long int target, lun; 63644f05562SScott Long 63744f05562SScott Long target=srb->pccb->ccb_h.target_id; 63844f05562SScott Long lun=srb->pccb->ccb_h.target_lun; 63944f05562SScott Long if((flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR)==0) { 64044f05562SScott Long if(acb->devstate[target][lun]==ARECA_RAID_GONE) { 64144f05562SScott Long acb->devstate[target][lun]=ARECA_RAID_GOOD; 64244f05562SScott Long } 64344f05562SScott Long srb->pccb->ccb_h.status |= CAM_REQ_CMP; 64444f05562SScott Long arcmsr_srb_complete(srb, 1); 64544f05562SScott Long } else { 64644f05562SScott Long switch(srb->arcmsr_cdb.DeviceStatus) { 64744f05562SScott Long case ARCMSR_DEV_SELECT_TIMEOUT: { 64844f05562SScott Long if(acb->devstate[target][lun]==ARECA_RAID_GOOD) { 64944f05562SScott Long printf( "arcmsr%d: select timeout" 65044f05562SScott Long ", raid volume was kicked out \n" 651ad6d6297SScott Long , acb->pci_unit); 652ad6d6297SScott Long } 65344f05562SScott Long acb->devstate[target][lun]=ARECA_RAID_GONE; 65444f05562SScott Long srb->pccb->ccb_h.status |= CAM_SEL_TIMEOUT; 65544f05562SScott Long arcmsr_srb_complete(srb, 1); 65644f05562SScott Long } 65744f05562SScott Long break; 65844f05562SScott Long case ARCMSR_DEV_ABORTED: 65944f05562SScott Long case ARCMSR_DEV_INIT_FAIL: { 66044f05562SScott Long acb->devstate[target][lun]=ARECA_RAID_GONE; 66144f05562SScott Long srb->pccb->ccb_h.status |= CAM_DEV_NOT_THERE; 66244f05562SScott Long arcmsr_srb_complete(srb, 1); 66344f05562SScott Long } 66444f05562SScott Long break; 66544f05562SScott Long case SCSISTAT_CHECK_CONDITION: { 66644f05562SScott Long acb->devstate[target][lun]=ARECA_RAID_GOOD; 66744f05562SScott Long arcmsr_report_sense_info(srb); 66844f05562SScott Long arcmsr_srb_complete(srb, 1); 66944f05562SScott Long } 67044f05562SScott Long break; 67144f05562SScott Long default: 67244f05562SScott Long printf("arcmsr%d: scsi id=%d lun=%d" 67344f05562SScott Long "isr get command error done," 67444f05562SScott Long "but got unknow DeviceStatus=0x%x \n" 67544f05562SScott Long , acb->pci_unit, target, lun 67644f05562SScott Long ,srb->arcmsr_cdb.DeviceStatus); 67744f05562SScott Long acb->devstate[target][lun]=ARECA_RAID_GONE; 67844f05562SScott Long srb->pccb->ccb_h.status |= CAM_UNCOR_PARITY; 67944f05562SScott Long /*unknow error or crc error just for retry*/ 68044f05562SScott Long arcmsr_srb_complete(srb, 1); 68144f05562SScott Long break; 68244f05562SScott Long } 68344f05562SScott Long } 68444f05562SScott Long return; 68544f05562SScott Long } 68644f05562SScott Long /* 68744f05562SScott Long ************************************************************************** 68844f05562SScott Long ************************************************************************** 68944f05562SScott Long */ 69044f05562SScott Long static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, u_int32_t flag_srb) 69144f05562SScott Long { 69244f05562SScott Long struct CommandControlBlock *srb; 69344f05562SScott Long 69444f05562SScott Long /* check if command done with no error*/ 69544f05562SScott Long srb=(struct CommandControlBlock *) 69644f05562SScott Long (acb->vir2phy_offset+(flag_srb << 5));/*frame must be 32 bytes aligned*/ 69744f05562SScott Long if((srb->acb!=acb) || (srb->startdone!=ARCMSR_SRB_START)) { 69844f05562SScott Long if(srb->startdone==ARCMSR_SRB_ABORTED) { 69944f05562SScott Long printf("arcmsr%d: srb='%p' isr got aborted command \n" 70044f05562SScott Long , acb->pci_unit, srb); 70144f05562SScott Long srb->pccb->ccb_h.status |= CAM_REQ_ABORTED; 70244f05562SScott Long arcmsr_srb_complete(srb, 1); 70344f05562SScott Long return; 70444f05562SScott Long } 70544f05562SScott Long printf("arcmsr%d: isr get an illegal srb command done" 70644f05562SScott Long "acb='%p' srb='%p' srbacb='%p' startdone=0x%x" 70744f05562SScott Long "srboutstandingcount=%d \n", 70844f05562SScott Long acb->pci_unit, acb, srb, srb->acb, 70944f05562SScott Long srb->startdone, acb->srboutstandingcount); 71044f05562SScott Long return; 71144f05562SScott Long } 71244f05562SScott Long arcmsr_report_srb_state(acb, srb, flag_srb); 71344f05562SScott Long return; 71444f05562SScott Long } 71544f05562SScott Long /* 71644f05562SScott Long ********************************************************************** 71744f05562SScott Long ********************************************************************** 71844f05562SScott Long */ 71944f05562SScott Long static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) 72044f05562SScott Long { 72144f05562SScott Long int i=0; 72244f05562SScott Long u_int32_t flag_srb; 72344f05562SScott Long 72444f05562SScott Long switch (acb->adapter_type) { 72544f05562SScott Long case ACB_ADAPTER_TYPE_A: { 72644f05562SScott Long u_int32_t outbound_intstatus; 72744f05562SScott Long 72844f05562SScott Long /*clear and abort all outbound posted Q*/ 72944f05562SScott Long outbound_intstatus=CHIP_REG_READ32(HBA_MessageUnit, 73044f05562SScott Long 0, outbound_intstatus) & acb->outbound_int_enable; 73144f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 73244f05562SScott Long 0, outbound_intstatus, outbound_intstatus);/*clear interrupt*/ 73344f05562SScott Long while(((flag_srb=CHIP_REG_READ32(HBA_MessageUnit, 73444f05562SScott Long 0, outbound_queueport)) != 0xFFFFFFFF) 73544f05562SScott Long && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { 73644f05562SScott Long arcmsr_drain_donequeue(acb, flag_srb); 73744f05562SScott Long } 73844f05562SScott Long } 73944f05562SScott Long break; 74044f05562SScott Long case ACB_ADAPTER_TYPE_B: { 74144f05562SScott Long struct HBB_MessageUnit *phbbmu=(struct HBB_MessageUnit *)acb->pmu; 74244f05562SScott Long 74344f05562SScott Long /*clear all outbound posted Q*/ 74444f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 74544f05562SScott Long 0, iop2drv_doorbell, 74644f05562SScott Long ARCMSR_DOORBELL_INT_CLEAR_PATTERN); /* clear doorbell interrupt */ 74744f05562SScott Long for(i=0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) { 74844f05562SScott Long if((flag_srb=phbbmu->done_qbuffer[i])!=0) { 74944f05562SScott Long phbbmu->done_qbuffer[i]=0; 75044f05562SScott Long arcmsr_drain_donequeue(acb, flag_srb); 75144f05562SScott Long } 75244f05562SScott Long phbbmu->post_qbuffer[i]=0; 75344f05562SScott Long }/*drain reply FIFO*/ 75444f05562SScott Long phbbmu->doneq_index=0; 75544f05562SScott Long phbbmu->postq_index=0; 75644f05562SScott Long } 75744f05562SScott Long break; 75844f05562SScott Long } 759f1c579b1SScott Long return; 760f1c579b1SScott Long } 761f1c579b1SScott Long /* 762f1c579b1SScott Long **************************************************************************** 763f1c579b1SScott Long **************************************************************************** 764f1c579b1SScott Long */ 765ad6d6297SScott Long static void arcmsr_iop_reset(struct AdapterControlBlock *acb) 766f1c579b1SScott Long { 767ad6d6297SScott Long struct CommandControlBlock *srb; 76844f05562SScott Long u_int32_t intmask_org; 769ad6d6297SScott Long u_int32_t i=0; 770f1c579b1SScott Long 77144f05562SScott Long if(acb->srboutstandingcount>0) { 77244f05562SScott Long /* disable all outbound interrupt */ 77344f05562SScott Long intmask_org=arcmsr_disable_allintr(acb); 77444f05562SScott Long /*clear and abort all outbound posted Q*/ 77544f05562SScott Long arcmsr_done4abort_postqueue(acb); 776f1c579b1SScott Long /* talk to iop 331 outstanding command aborted*/ 777ad6d6297SScott Long arcmsr_abort_allcmd(acb); 778ad6d6297SScott Long for(i=0;i<ARCMSR_MAX_FREESRB_NUM;i++) { 779ad6d6297SScott Long srb=acb->psrb_pool[i]; 780ad6d6297SScott Long if(srb->startdone==ARCMSR_SRB_START) { 781ad6d6297SScott Long srb->startdone=ARCMSR_SRB_ABORTED; 782ad6d6297SScott Long srb->pccb->ccb_h.status |= CAM_REQ_ABORTED; 783ad6d6297SScott Long arcmsr_srb_complete(srb, 1); 784f1c579b1SScott Long } 785f1c579b1SScott Long } 786f1c579b1SScott Long /* enable all outbound interrupt */ 78744f05562SScott Long arcmsr_enable_allintr(acb, intmask_org); 788f1c579b1SScott Long } 789ad6d6297SScott Long atomic_set_int(&acb->srboutstandingcount, 0); 790ad6d6297SScott Long acb->workingsrb_doneindex=0; 791ad6d6297SScott Long acb->workingsrb_startindex=0; 792f1c579b1SScott Long return; 793f1c579b1SScott Long } 794f1c579b1SScott Long /* 795f1c579b1SScott Long ********************************************************************** 796f1c579b1SScott Long ********************************************************************** 797f1c579b1SScott Long */ 79844f05562SScott Long static void arcmsr_build_srb(struct CommandControlBlock *srb, 79944f05562SScott Long bus_dma_segment_t *dm_segs, u_int32_t nseg) 800f1c579b1SScott Long { 801ad6d6297SScott Long struct ARCMSR_CDB * arcmsr_cdb= &srb->arcmsr_cdb; 802ad6d6297SScott Long u_int8_t * psge=(u_int8_t *)&arcmsr_cdb->u; 803ad6d6297SScott Long u_int32_t address_lo, address_hi; 804ad6d6297SScott Long union ccb * pccb=srb->pccb; 805f1c579b1SScott Long struct ccb_scsiio * pcsio= &pccb->csio; 806ad6d6297SScott Long u_int32_t arccdbsize=0x30; 807f1c579b1SScott Long 808ad6d6297SScott Long memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB)); 809ad6d6297SScott Long arcmsr_cdb->Bus=0; 810ad6d6297SScott Long arcmsr_cdb->TargetID=pccb->ccb_h.target_id; 811ad6d6297SScott Long arcmsr_cdb->LUN=pccb->ccb_h.target_lun; 812ad6d6297SScott Long arcmsr_cdb->Function=1; 813ad6d6297SScott Long arcmsr_cdb->CdbLength=(u_int8_t)pcsio->cdb_len; 81444f05562SScott Long arcmsr_cdb->Context=0; 815ad6d6297SScott Long bcopy(pcsio->cdb_io.cdb_bytes, arcmsr_cdb->Cdb, pcsio->cdb_len); 816ad6d6297SScott Long if(nseg != 0) { 817ad6d6297SScott Long struct AdapterControlBlock *acb=srb->acb; 818f1c579b1SScott Long bus_dmasync_op_t op; 819ad6d6297SScott Long u_int32_t length, i, cdb_sgcount=0; 820f1c579b1SScott Long 821ad6d6297SScott Long if((pccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 822ad6d6297SScott Long op=BUS_DMASYNC_PREREAD; 823ad6d6297SScott Long } else { 824ad6d6297SScott Long op=BUS_DMASYNC_PREWRITE; 825ad6d6297SScott Long arcmsr_cdb->Flags|=ARCMSR_CDB_FLAG_WRITE; 826ad6d6297SScott Long srb->srb_flags|=SRB_FLAG_WRITE; 827ad6d6297SScott Long } 828ad6d6297SScott Long bus_dmamap_sync(acb->dm_segs_dmat, srb->dm_segs_dmamap, op); 829ad6d6297SScott Long for(i=0;i<nseg;i++) { 830f1c579b1SScott Long /* Get the physical address of the current data pointer */ 831ad6d6297SScott Long length=arcmsr_htole32(dm_segs[i].ds_len); 832ad6d6297SScott Long address_lo=arcmsr_htole32(dma_addr_lo32(dm_segs[i].ds_addr)); 833ad6d6297SScott Long address_hi=arcmsr_htole32(dma_addr_hi32(dm_segs[i].ds_addr)); 834ad6d6297SScott Long if(address_hi==0) { 835ad6d6297SScott Long struct SG32ENTRY * pdma_sg=(struct SG32ENTRY *)psge; 836f1c579b1SScott Long pdma_sg->address=address_lo; 837f1c579b1SScott Long pdma_sg->length=length; 838ad6d6297SScott Long psge += sizeof(struct SG32ENTRY); 839ad6d6297SScott Long arccdbsize += sizeof(struct SG32ENTRY); 840ad6d6297SScott Long } else { 841ad6d6297SScott Long u_int32_t sg64s_size=0, tmplength=length; 842f1c579b1SScott Long 843ad6d6297SScott Long while(1) { 844ad6d6297SScott Long u_int64_t span4G, length0; 845ad6d6297SScott Long struct SG64ENTRY * pdma_sg=(struct SG64ENTRY *)psge; 846f1c579b1SScott Long 847ad6d6297SScott Long span4G=(u_int64_t)address_lo + tmplength; 848f1c579b1SScott Long pdma_sg->addresshigh=address_hi; 849f1c579b1SScott Long pdma_sg->address=address_lo; 850ad6d6297SScott Long if(span4G > 0x100000000) { 851f1c579b1SScott Long /*see if cross 4G boundary*/ 852f1c579b1SScott Long length0=0x100000000-address_lo; 853ad6d6297SScott Long pdma_sg->length=(u_int32_t)length0|IS_SG64_ADDR; 854f1c579b1SScott Long address_hi=address_hi+1; 855f1c579b1SScott Long address_lo=0; 856ad6d6297SScott Long tmplength=tmplength-(u_int32_t)length0; 857ad6d6297SScott Long sg64s_size += sizeof(struct SG64ENTRY); 858ad6d6297SScott Long psge += sizeof(struct SG64ENTRY); 859f1c579b1SScott Long cdb_sgcount++; 860ad6d6297SScott Long } else { 861f1c579b1SScott Long pdma_sg->length=tmplength|IS_SG64_ADDR; 862ad6d6297SScott Long sg64s_size += sizeof(struct SG64ENTRY); 863ad6d6297SScott Long psge += sizeof(struct SG64ENTRY); 864f1c579b1SScott Long break; 865f1c579b1SScott Long } 866f1c579b1SScott Long } 867f1c579b1SScott Long arccdbsize += sg64s_size; 868f1c579b1SScott Long } 869f1c579b1SScott Long cdb_sgcount++; 870f1c579b1SScott Long } 871ad6d6297SScott Long arcmsr_cdb->sgcount=(u_int8_t)cdb_sgcount; 872ad6d6297SScott Long arcmsr_cdb->DataLength=pcsio->dxfer_len; 873ad6d6297SScott Long if( arccdbsize > 256) { 874ad6d6297SScott Long arcmsr_cdb->Flags|=ARCMSR_CDB_FLAG_SGL_BSIZE; 875f1c579b1SScott Long } 876f1c579b1SScott Long } 877f1c579b1SScott Long return; 878f1c579b1SScott Long } 879f1c579b1SScott Long /* 880f1c579b1SScott Long ************************************************************************** 881f1c579b1SScott Long ************************************************************************** 882f1c579b1SScott Long */ 883ad6d6297SScott Long static void arcmsr_post_srb(struct AdapterControlBlock *acb, struct CommandControlBlock *srb) 884f1c579b1SScott Long { 885ad6d6297SScott Long u_int32_t cdb_shifted_phyaddr=(u_int32_t) srb->cdb_shifted_phyaddr; 886ad6d6297SScott Long struct ARCMSR_CDB * arcmsr_cdb=(struct ARCMSR_CDB *)&srb->arcmsr_cdb; 887f1c579b1SScott Long 888ad6d6297SScott Long bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, 889ad6d6297SScott Long (srb->srb_flags & SRB_FLAG_WRITE) ? BUS_DMASYNC_POSTWRITE:BUS_DMASYNC_POSTREAD); 890ad6d6297SScott Long atomic_add_int(&acb->srboutstandingcount, 1); 891ad6d6297SScott Long srb->startdone=ARCMSR_SRB_START; 89244f05562SScott Long switch (acb->adapter_type) { 89344f05562SScott Long case ACB_ADAPTER_TYPE_A: { 894ad6d6297SScott Long if(arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { 89544f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 89644f05562SScott Long 0, inbound_queueport, 89744f05562SScott Long cdb_shifted_phyaddr|ARCMSR_SRBPOST_FLAG_SGL_BSIZE); 898ad6d6297SScott Long } else { 89944f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 90044f05562SScott Long 0, inbound_queueport, cdb_shifted_phyaddr); 90144f05562SScott Long } 90244f05562SScott Long } 90344f05562SScott Long break; 90444f05562SScott Long case ACB_ADAPTER_TYPE_B: { 90544f05562SScott Long struct HBB_MessageUnit *phbbmu=(struct HBB_MessageUnit *)acb->pmu; 90644f05562SScott Long int ending_index, index; 90744f05562SScott Long 90844f05562SScott Long index=phbbmu->postq_index; 90944f05562SScott Long ending_index=((index+1)%ARCMSR_MAX_HBB_POSTQUEUE); 91044f05562SScott Long phbbmu->post_qbuffer[ending_index]=0; 91144f05562SScott Long if(arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { 91244f05562SScott Long phbbmu->post_qbuffer[index]= 91344f05562SScott Long cdb_shifted_phyaddr|ARCMSR_SRBPOST_FLAG_SGL_BSIZE; 91444f05562SScott Long } else { 91544f05562SScott Long phbbmu->post_qbuffer[index]= 91644f05562SScott Long cdb_shifted_phyaddr; 91744f05562SScott Long } 91844f05562SScott Long index++; 91944f05562SScott Long index %= ARCMSR_MAX_HBB_POSTQUEUE; /*if last index number set it to 0 */ 92044f05562SScott Long phbbmu->postq_index=index; 92144f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 92244f05562SScott Long 0, drv2iop_doorbell, ARCMSR_DRV2IOP_CDB_POSTED); 92344f05562SScott Long } 92444f05562SScott Long break; 925f1c579b1SScott Long } 926f1c579b1SScott Long return; 927f1c579b1SScott Long } 928f1c579b1SScott Long /* 92944f05562SScott Long ************************************************************************ 93044f05562SScott Long ************************************************************************ 93144f05562SScott Long */ 93244f05562SScott Long static struct QBUFFER * arcmsr_get_iop_rqbuffer( struct AdapterControlBlock *acb) 93344f05562SScott Long { 93444f05562SScott Long struct QBUFFER *qbuffer=NULL; 93544f05562SScott Long 93644f05562SScott Long switch (acb->adapter_type) { 93744f05562SScott Long case ACB_ADAPTER_TYPE_A: { 93844f05562SScott Long struct HBA_MessageUnit *phbamu=(struct HBA_MessageUnit *)acb->pmu; 93944f05562SScott Long 94044f05562SScott Long qbuffer=(struct QBUFFER *)&phbamu->message_rbuffer; 94144f05562SScott Long } 94244f05562SScott Long break; 94344f05562SScott Long case ACB_ADAPTER_TYPE_B: { 94444f05562SScott Long struct HBB_MessageUnit *phbbmu=(struct HBB_MessageUnit *)acb->pmu; 94544f05562SScott Long 94644f05562SScott Long qbuffer=(struct QBUFFER *)&phbbmu->hbb_rwbuffer->message_rbuffer; 94744f05562SScott Long } 94844f05562SScott Long break; 94944f05562SScott Long } 95044f05562SScott Long return(qbuffer); 95144f05562SScott Long } 95244f05562SScott Long /* 95344f05562SScott Long ************************************************************************ 95444f05562SScott Long ************************************************************************ 95544f05562SScott Long */ 95644f05562SScott Long static struct QBUFFER * arcmsr_get_iop_wqbuffer( struct AdapterControlBlock *acb) 95744f05562SScott Long { 95844f05562SScott Long struct QBUFFER *qbuffer=NULL; 95944f05562SScott Long 96044f05562SScott Long switch (acb->adapter_type) { 96144f05562SScott Long case ACB_ADAPTER_TYPE_A: { 96244f05562SScott Long struct HBA_MessageUnit *phbamu=(struct HBA_MessageUnit *)acb->pmu; 96344f05562SScott Long 96444f05562SScott Long qbuffer=(struct QBUFFER *)&phbamu->message_wbuffer; 96544f05562SScott Long } 96644f05562SScott Long break; 96744f05562SScott Long case ACB_ADAPTER_TYPE_B: { 96844f05562SScott Long struct HBB_MessageUnit *phbbmu=(struct HBB_MessageUnit *)acb->pmu; 96944f05562SScott Long 97044f05562SScott Long qbuffer=(struct QBUFFER *)&phbbmu->hbb_rwbuffer->message_wbuffer; 97144f05562SScott Long } 97244f05562SScott Long break; 97344f05562SScott Long } 97444f05562SScott Long return(qbuffer); 97544f05562SScott Long } 97644f05562SScott Long /* 97744f05562SScott Long ************************************************************************** 97844f05562SScott Long ************************************************************************** 97944f05562SScott Long */ 98044f05562SScott Long static void arcmsr_iop_message_read(struct AdapterControlBlock *acb) 98144f05562SScott Long { 98244f05562SScott Long switch (acb->adapter_type) { 98344f05562SScott Long case ACB_ADAPTER_TYPE_A: { 98444f05562SScott Long /* let IOP know data has been read */ 98544f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 98644f05562SScott Long 0, inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_READ_OK); 98744f05562SScott Long } 98844f05562SScott Long break; 98944f05562SScott Long case ACB_ADAPTER_TYPE_B: { 99044f05562SScott Long /* let IOP know data has been read */ 99144f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 99244f05562SScott Long 0, drv2iop_doorbell, ARCMSR_DRV2IOP_DATA_READ_OK); 99344f05562SScott Long } 99444f05562SScott Long break; 99544f05562SScott Long } 99644f05562SScott Long return; 99744f05562SScott Long } 99844f05562SScott Long /* 99944f05562SScott Long ************************************************************************** 100044f05562SScott Long ************************************************************************** 100144f05562SScott Long */ 100244f05562SScott Long static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb) 100344f05562SScott Long { 100444f05562SScott Long switch (acb->adapter_type) { 100544f05562SScott Long case ACB_ADAPTER_TYPE_A: { 100644f05562SScott Long /* 100744f05562SScott Long ** push inbound doorbell tell iop, driver data write ok 100844f05562SScott Long ** and wait reply on next hwinterrupt for next Qbuffer post 100944f05562SScott Long */ 101044f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 101144f05562SScott Long 0, inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK); 101244f05562SScott Long } 101344f05562SScott Long break; 101444f05562SScott Long case ACB_ADAPTER_TYPE_B: { 101544f05562SScott Long /* 101644f05562SScott Long ** push inbound doorbell tell iop, driver data write ok 101744f05562SScott Long ** and wait reply on next hwinterrupt for next Qbuffer post 101844f05562SScott Long */ 101944f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 102044f05562SScott Long 0, drv2iop_doorbell, ARCMSR_DRV2IOP_DATA_WRITE_OK); 102144f05562SScott Long } 102244f05562SScott Long break; 102344f05562SScott Long } 102444f05562SScott Long } 102544f05562SScott Long /* 1026f1c579b1SScott Long ********************************************************************** 1027f1c579b1SScott Long ********************************************************************** 1028f1c579b1SScott Long */ 102944f05562SScott Long static void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb) 1030f1c579b1SScott Long { 1031ad6d6297SScott Long u_int8_t *pQbuffer; 103244f05562SScott Long struct QBUFFER *pwbuffer; 103344f05562SScott Long u_int8_t * iop_data; 103444f05562SScott Long int32_t allxfer_len=0; 1035f1c579b1SScott Long 103644f05562SScott Long pwbuffer=arcmsr_get_iop_wqbuffer(acb); 103744f05562SScott Long iop_data=(u_int8_t *)pwbuffer->data; 103844f05562SScott Long if(acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READ) { 103944f05562SScott Long acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READ); 104044f05562SScott Long while((acb->wqbuf_firstindex!=acb->wqbuf_lastindex) 104144f05562SScott Long && (allxfer_len<124)) { 1042ad6d6297SScott Long pQbuffer=&acb->wqbuffer[acb->wqbuf_firstindex]; 1043f1c579b1SScott Long memcpy(iop_data, pQbuffer, 1); 1044ad6d6297SScott Long acb->wqbuf_firstindex++; 104544f05562SScott Long acb->wqbuf_firstindex %=ARCMSR_MAX_QBUFFER; /*if last index number set it to 0 */ 1046f1c579b1SScott Long iop_data++; 1047f1c579b1SScott Long allxfer_len++; 1048f1c579b1SScott Long } 1049f1c579b1SScott Long pwbuffer->data_len=allxfer_len; 1050f1c579b1SScott Long /* 1051f1c579b1SScott Long ** push inbound doorbell and wait reply at hwinterrupt routine for next Qbuffer post 1052f1c579b1SScott Long */ 105344f05562SScott Long arcmsr_iop_message_wrote(acb); 1054ad6d6297SScott Long } 1055f1c579b1SScott Long return; 1056f1c579b1SScott Long } 1057f1c579b1SScott Long /* 1058f1c579b1SScott Long ************************************************************************ 1059f1c579b1SScott Long ************************************************************************ 1060f1c579b1SScott Long */ 106144f05562SScott Long static void arcmsr_stop_hba_bgrb(struct AdapterControlBlock *acb) 1062f1c579b1SScott Long { 1063ad6d6297SScott Long acb->acb_flags &=~ACB_F_MSG_START_BGRB; 106444f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 106544f05562SScott Long 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_STOP_BGRB); 106644f05562SScott Long if(!arcmsr_hba_wait_msgint_ready(acb)) { 1067ad6d6297SScott Long printf("arcmsr%d: wait 'stop adapter rebulid' timeout \n" 1068ad6d6297SScott Long , acb->pci_unit); 1069ad6d6297SScott Long } 1070f1c579b1SScott Long return; 1071f1c579b1SScott Long } 1072f1c579b1SScott Long /* 1073f1c579b1SScott Long ************************************************************************ 1074f1c579b1SScott Long ************************************************************************ 1075f1c579b1SScott Long */ 107644f05562SScott Long static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb) 107744f05562SScott Long { 107844f05562SScott Long acb->acb_flags &= ~ACB_F_MSG_START_BGRB; 107944f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 108044f05562SScott Long 0, drv2iop_doorbell, ARCMSR_MESSAGE_STOP_BGRB); 108144f05562SScott Long if(!arcmsr_hbb_wait_msgint_ready(acb)) { 108244f05562SScott Long printf( "arcmsr%d: wait 'stop adapter rebulid' timeout \n" 108344f05562SScott Long , acb->pci_unit); 108444f05562SScott Long } 108544f05562SScott Long return; 108644f05562SScott Long } 108744f05562SScott Long /* 108844f05562SScott Long ************************************************************************ 108944f05562SScott Long ************************************************************************ 109044f05562SScott Long */ 109144f05562SScott Long static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) 109244f05562SScott Long { 109344f05562SScott Long switch (acb->adapter_type) { 109444f05562SScott Long case ACB_ADAPTER_TYPE_A: { 109544f05562SScott Long arcmsr_stop_hba_bgrb(acb); 109644f05562SScott Long } 109744f05562SScott Long break; 109844f05562SScott Long case ACB_ADAPTER_TYPE_B: { 109944f05562SScott Long arcmsr_stop_hbb_bgrb(acb); 110044f05562SScott Long } 110144f05562SScott Long break; 110244f05562SScott Long } 110344f05562SScott Long return; 110444f05562SScott Long } 110544f05562SScott Long /* 110644f05562SScott Long ************************************************************************ 110744f05562SScott Long ************************************************************************ 110844f05562SScott Long */ 1109ad6d6297SScott Long static void arcmsr_poll(struct cam_sim * psim) 1110f1c579b1SScott Long { 1111579ec1a5SScott Long struct AdapterControlBlock *acb; 1112579ec1a5SScott Long 1113579ec1a5SScott Long acb = (struct AdapterControlBlock *)cam_sim_softc(psim); 1114579ec1a5SScott Long #if __FreeBSD_version < 700025 1115579ec1a5SScott Long ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); 1116579ec1a5SScott Long #endif 1117579ec1a5SScott Long arcmsr_interrupt(acb); 1118579ec1a5SScott Long #if __FreeBSD_version < 700025 1119579ec1a5SScott Long ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); 1120579ec1a5SScott Long #endif 1121f1c579b1SScott Long return; 1122f1c579b1SScott Long } 1123f1c579b1SScott Long /* 1124f1c579b1SScott Long ********************************************************************** 1125f1c579b1SScott Long ********************************************************************** 1126f1c579b1SScott Long */ 11275878cbecSScott Long static void arcmsr_intr_handler(void *arg) 11285878cbecSScott Long { 11295878cbecSScott Long struct AdapterControlBlock *acb=(struct AdapterControlBlock *)arg; 11305878cbecSScott Long 11315878cbecSScott Long ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); 11325878cbecSScott Long arcmsr_interrupt(acb); 11335878cbecSScott Long ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); 11345878cbecSScott Long } 11355878cbecSScott Long /* 113644f05562SScott Long ************************************************************************** 113744f05562SScott Long ************************************************************************** 11385878cbecSScott Long */ 113944f05562SScott Long static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb) 1140f1c579b1SScott Long { 114144f05562SScott Long struct QBUFFER *prbuffer; 1142ad6d6297SScott Long u_int8_t *pQbuffer; 114344f05562SScott Long u_int8_t *iop_data; 114444f05562SScott Long int my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex; 1145ad6d6297SScott Long 1146f1c579b1SScott Long /*check this iop data if overflow my rqbuffer*/ 1147ad6d6297SScott Long rqbuf_lastindex=acb->rqbuf_lastindex; 1148ad6d6297SScott Long rqbuf_firstindex=acb->rqbuf_firstindex; 114944f05562SScott Long prbuffer=arcmsr_get_iop_rqbuffer(acb); 115044f05562SScott Long iop_data=(u_int8_t *)prbuffer->data; 1151f1c579b1SScott Long iop_len=prbuffer->data_len; 1152f1c579b1SScott Long my_empty_len=(rqbuf_firstindex-rqbuf_lastindex-1)&(ARCMSR_MAX_QBUFFER-1); 1153ad6d6297SScott Long if(my_empty_len>=iop_len) { 1154ad6d6297SScott Long while(iop_len > 0) { 115544f05562SScott Long pQbuffer=&acb->rqbuffer[rqbuf_lastindex]; 1156f1c579b1SScott Long memcpy(pQbuffer, iop_data, 1); 115744f05562SScott Long rqbuf_lastindex++; 115844f05562SScott Long rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;/*if last index number set it to 0 */ 1159f1c579b1SScott Long iop_data++; 1160f1c579b1SScott Long iop_len--; 1161f1c579b1SScott Long } 116244f05562SScott Long acb->rqbuf_lastindex=rqbuf_lastindex; 116344f05562SScott Long arcmsr_iop_message_read(acb); 116444f05562SScott Long /*signature, let IOP know data has been read */ 1165ad6d6297SScott Long } else { 1166ad6d6297SScott Long acb->acb_flags|=ACB_F_IOPDATA_OVERFLOW; 1167f1c579b1SScott Long } 116844f05562SScott Long return; 1169f1c579b1SScott Long } 1170f1c579b1SScott Long /* 117144f05562SScott Long ************************************************************************** 117244f05562SScott Long ************************************************************************** 117344f05562SScott Long */ 117444f05562SScott Long static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb) 117544f05562SScott Long { 117644f05562SScott Long acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READ; 117744f05562SScott Long /* 117844f05562SScott Long ***************************************************************** 117944f05562SScott Long ** check if there are any mail packages from user space program 118044f05562SScott Long ** in my post bag, now is the time to send them into Areca's firmware 118144f05562SScott Long ***************************************************************** 1182f1c579b1SScott Long */ 1183ad6d6297SScott Long if(acb->wqbuf_firstindex!=acb->wqbuf_lastindex) { 1184ad6d6297SScott Long u_int8_t *pQbuffer; 118544f05562SScott Long struct QBUFFER *pwbuffer; 118644f05562SScott Long u_int8_t *iop_data; 118744f05562SScott Long int allxfer_len=0; 1188f1c579b1SScott Long 118944f05562SScott Long acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READ); 119044f05562SScott Long pwbuffer=arcmsr_get_iop_wqbuffer(acb); 119144f05562SScott Long iop_data=(u_int8_t *)pwbuffer->data; 119244f05562SScott Long while((acb->wqbuf_firstindex!=acb->wqbuf_lastindex) 119344f05562SScott Long && (allxfer_len<124)) { 1194ad6d6297SScott Long pQbuffer=&acb->wqbuffer[acb->wqbuf_firstindex]; 1195f1c579b1SScott Long memcpy(iop_data, pQbuffer, 1); 1196ad6d6297SScott Long acb->wqbuf_firstindex++; 119744f05562SScott Long acb->wqbuf_firstindex %=ARCMSR_MAX_QBUFFER; /*if last index number set it to 0 */ 1198f1c579b1SScott Long iop_data++; 1199f1c579b1SScott Long allxfer_len++; 1200f1c579b1SScott Long } 1201f1c579b1SScott Long pwbuffer->data_len=allxfer_len; 1202f1c579b1SScott Long /* 1203ad6d6297SScott Long ** push inbound doorbell tell iop driver data write ok 1204ad6d6297SScott Long ** and wait reply on next hwinterrupt for next Qbuffer post 1205f1c579b1SScott Long */ 120644f05562SScott Long arcmsr_iop_message_wrote(acb); 1207f1c579b1SScott Long } 1208ad6d6297SScott Long if(acb->wqbuf_firstindex==acb->wqbuf_lastindex) { 1209ad6d6297SScott Long acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED; 1210f1c579b1SScott Long } 121144f05562SScott Long return; 1212f1c579b1SScott Long } 121344f05562SScott Long /* 121444f05562SScott Long ************************************************************************** 121544f05562SScott Long ************************************************************************** 121644f05562SScott Long */ 121744f05562SScott Long static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb) 121844f05562SScott Long { 121944f05562SScott Long u_int32_t outbound_doorbell; 122044f05562SScott Long 122144f05562SScott Long /* 122244f05562SScott Long ******************************************************************* 122344f05562SScott Long ** Maybe here we need to check wrqbuffer_lock is lock or not 122444f05562SScott Long ** DOORBELL: din! don! 122544f05562SScott Long ** check if there are any mail need to pack from firmware 122644f05562SScott Long ******************************************************************* 122744f05562SScott Long */ 122844f05562SScott Long outbound_doorbell=CHIP_REG_READ32(HBA_MessageUnit, 122944f05562SScott Long 0, outbound_doorbell); 123044f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 123144f05562SScott Long 0, outbound_doorbell, outbound_doorbell); /* clear doorbell interrupt */ 123244f05562SScott Long if(outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { 123344f05562SScott Long arcmsr_iop2drv_data_wrote_handle(acb); 1234ad6d6297SScott Long } 123544f05562SScott Long if(outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) { 123644f05562SScott Long arcmsr_iop2drv_data_read_handle(acb); 123744f05562SScott Long } 123844f05562SScott Long return; 123944f05562SScott Long } 124044f05562SScott Long /* 124144f05562SScott Long ************************************************************************** 124244f05562SScott Long ************************************************************************** 124344f05562SScott Long */ 124444f05562SScott Long static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb) 124544f05562SScott Long { 124644f05562SScott Long u_int32_t flag_srb; 124744f05562SScott Long 1248f1c579b1SScott Long /* 1249f1c579b1SScott Long ***************************************************************************** 1250f1c579b1SScott Long ** areca cdb command done 1251f1c579b1SScott Long ***************************************************************************** 1252f1c579b1SScott Long */ 125344f05562SScott Long bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, 125444f05562SScott Long BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 125544f05562SScott Long while((flag_srb=CHIP_REG_READ32(HBA_MessageUnit, 125644f05562SScott Long 0, outbound_queueport)) != 0xFFFFFFFF) { 1257f1c579b1SScott Long /* check if command done with no error*/ 125844f05562SScott Long arcmsr_drain_donequeue(acb, flag_srb); 125944f05562SScott Long } /*drain reply FIFO*/ 126044f05562SScott Long return; 1261f1c579b1SScott Long } 126244f05562SScott Long /* 126344f05562SScott Long ************************************************************************** 126444f05562SScott Long ************************************************************************** 126544f05562SScott Long */ 126644f05562SScott Long static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb) 126744f05562SScott Long { 126844f05562SScott Long struct HBB_MessageUnit *phbbmu=(struct HBB_MessageUnit *)acb->pmu; 126944f05562SScott Long u_int32_t flag_srb; 127044f05562SScott Long int index; 127144f05562SScott Long 127244f05562SScott Long /* 127344f05562SScott Long ***************************************************************************** 127444f05562SScott Long ** areca cdb command done 127544f05562SScott Long ***************************************************************************** 127644f05562SScott Long */ 127744f05562SScott Long bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, 127844f05562SScott Long BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 127944f05562SScott Long index=phbbmu->doneq_index; 128044f05562SScott Long while((flag_srb=phbbmu->done_qbuffer[index]) != 0) { 128144f05562SScott Long phbbmu->done_qbuffer[index]=0; 128244f05562SScott Long index++; 128344f05562SScott Long index %= ARCMSR_MAX_HBB_POSTQUEUE; /*if last index number set it to 0 */ 128444f05562SScott Long phbbmu->doneq_index=index; 128544f05562SScott Long /* check if command done with no error*/ 128644f05562SScott Long arcmsr_drain_donequeue(acb, flag_srb); 128744f05562SScott Long } /*drain reply FIFO*/ 128844f05562SScott Long return; 1289f1c579b1SScott Long } 129044f05562SScott Long /* 129144f05562SScott Long ********************************************************************** 129244f05562SScott Long ********************************************************************** 129344f05562SScott Long */ 129444f05562SScott Long static void arcmsr_handle_hba_isr( struct AdapterControlBlock *acb) 129544f05562SScott Long { 129644f05562SScott Long u_int32_t outbound_intstatus; 129744f05562SScott Long /* 129844f05562SScott Long ********************************************* 129944f05562SScott Long ** check outbound intstatus 130044f05562SScott Long ********************************************* 130144f05562SScott Long */ 130244f05562SScott Long outbound_intstatus=CHIP_REG_READ32(HBA_MessageUnit, 130344f05562SScott Long 0, outbound_intstatus) & acb->outbound_int_enable; 130444f05562SScott Long if(!outbound_intstatus) { 130544f05562SScott Long /*it must be share irq*/ 130644f05562SScott Long return; 1307f1c579b1SScott Long } 130844f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 130944f05562SScott Long 0, outbound_intstatus, outbound_intstatus);/*clear interrupt*/ 131044f05562SScott Long /* MU doorbell interrupts*/ 131144f05562SScott Long if(outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) { 131244f05562SScott Long arcmsr_hba_doorbell_isr(acb); 1313f1c579b1SScott Long } 131444f05562SScott Long /* MU post queue interrupts*/ 131544f05562SScott Long if(outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) { 131644f05562SScott Long arcmsr_hba_postqueue_isr(acb); 131744f05562SScott Long } 131844f05562SScott Long return; 131944f05562SScott Long } 132044f05562SScott Long /* 132144f05562SScott Long ********************************************************************** 132244f05562SScott Long ********************************************************************** 132344f05562SScott Long */ 132444f05562SScott Long static void arcmsr_handle_hbb_isr( struct AdapterControlBlock *acb) 132544f05562SScott Long { 132644f05562SScott Long u_int32_t outbound_doorbell; 132744f05562SScott Long /* 132844f05562SScott Long ********************************************* 132944f05562SScott Long ** check outbound intstatus 133044f05562SScott Long ********************************************* 133144f05562SScott Long */ 133244f05562SScott Long outbound_doorbell=CHIP_REG_READ32(HBB_DOORBELL, 0, iop2drv_doorbell) & acb->outbound_int_enable; 133344f05562SScott Long if(!outbound_doorbell) { 133444f05562SScott Long /*it must be share irq*/ 133544f05562SScott Long return; 133644f05562SScott Long } 133744f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 0, iop2drv_doorbell, ~outbound_doorbell); /* clear doorbell interrupt */ 133844f05562SScott Long CHIP_REG_READ32(HBB_DOORBELL, 0, iop2drv_doorbell); 133944f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_DRV2IOP_END_OF_INTERRUPT); 134044f05562SScott Long /* MU ioctl transfer doorbell interrupts*/ 134144f05562SScott Long if(outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) { 134244f05562SScott Long arcmsr_iop2drv_data_wrote_handle(acb); 134344f05562SScott Long } 134444f05562SScott Long if(outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) { 134544f05562SScott Long arcmsr_iop2drv_data_read_handle(acb); 134644f05562SScott Long } 134744f05562SScott Long /* MU post queue interrupts*/ 134844f05562SScott Long if(outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) { 134944f05562SScott Long arcmsr_hbb_postqueue_isr(acb); 135044f05562SScott Long } 135144f05562SScott Long return; 135244f05562SScott Long } 135344f05562SScott Long /* 135444f05562SScott Long ****************************************************************************** 135544f05562SScott Long ****************************************************************************** 135644f05562SScott Long */ 135744f05562SScott Long static void arcmsr_interrupt(struct AdapterControlBlock *acb) 135844f05562SScott Long { 135944f05562SScott Long switch (acb->adapter_type) { 136044f05562SScott Long case ACB_ADAPTER_TYPE_A: 136144f05562SScott Long arcmsr_handle_hba_isr(acb); 1362f1c579b1SScott Long break; 136344f05562SScott Long case ACB_ADAPTER_TYPE_B: 136444f05562SScott Long arcmsr_handle_hbb_isr(acb); 1365f1c579b1SScott Long break; 1366f1c579b1SScott Long default: 136744f05562SScott Long printf("arcmsr%d: interrupt service," 136844f05562SScott Long " unknow adapter type =%d\n", acb->pci_unit, acb->adapter_type); 1369f1c579b1SScott Long break; 1370f1c579b1SScott Long } 1371f1c579b1SScott Long return; 1372f1c579b1SScott Long } 1373f1c579b1SScott Long /* 1374ad6d6297SScott Long ******************************************************************************* 1375ad6d6297SScott Long ** 1376ad6d6297SScott Long ******************************************************************************* 1377ad6d6297SScott Long */ 1378ad6d6297SScott Long static void arcmsr_iop_parking(struct AdapterControlBlock *acb) 1379ad6d6297SScott Long { 1380ad6d6297SScott Long if(acb!=NULL) { 1381ad6d6297SScott Long /* stop adapter background rebuild */ 1382ad6d6297SScott Long if(acb->acb_flags & ACB_F_MSG_START_BGRB) { 1383ad6d6297SScott Long arcmsr_stop_adapter_bgrb(acb); 1384ad6d6297SScott Long arcmsr_flush_adapter_cache(acb); 1385ad6d6297SScott Long } 1386ad6d6297SScott Long } 1387ad6d6297SScott Long } 1388ad6d6297SScott Long /* 1389f1c579b1SScott Long *********************************************************************** 1390f1c579b1SScott Long ** 1391f1c579b1SScott Long ************************************************************************ 1392f1c579b1SScott Long */ 1393ad6d6297SScott Long u_int32_t arcmsr_iop_ioctlcmd(struct AdapterControlBlock *acb, u_int32_t ioctl_cmd, caddr_t arg) 1394f1c579b1SScott Long { 1395ad6d6297SScott Long struct CMD_MESSAGE_FIELD * pcmdmessagefld; 1396ad6d6297SScott Long u_int32_t retvalue=EINVAL; 1397f1c579b1SScott Long 1398ad6d6297SScott Long pcmdmessagefld=(struct CMD_MESSAGE_FIELD *) arg; 1399ad6d6297SScott Long if(memcmp(pcmdmessagefld->cmdmessage.Signature, "ARCMSR", 6)!=0) { 1400ad6d6297SScott Long return retvalue; 1401f1c579b1SScott Long } 1402ad6d6297SScott Long ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); 1403ad6d6297SScott Long switch(ioctl_cmd) { 1404ad6d6297SScott Long case ARCMSR_MESSAGE_READ_RQBUFFER: { 1405ad6d6297SScott Long u_int8_t * pQbuffer; 1406ad6d6297SScott Long u_int8_t * ptmpQbuffer=pcmdmessagefld->messagedatabuffer; 1407ad6d6297SScott Long u_int32_t allxfer_len=0; 1408f1c579b1SScott Long 140944f05562SScott Long while((acb->rqbuf_firstindex!=acb->rqbuf_lastindex) 141044f05562SScott Long && (allxfer_len<1031)) { 1411f1c579b1SScott Long /*copy READ QBUFFER to srb*/ 1412ad6d6297SScott Long pQbuffer= &acb->rqbuffer[acb->rqbuf_firstindex]; 1413f1c579b1SScott Long memcpy(ptmpQbuffer, pQbuffer, 1); 1414ad6d6297SScott Long acb->rqbuf_firstindex++; 1415ad6d6297SScott Long acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; 1416ad6d6297SScott Long /*if last index number set it to 0 */ 1417f1c579b1SScott Long ptmpQbuffer++; 1418f1c579b1SScott Long allxfer_len++; 1419f1c579b1SScott Long } 1420ad6d6297SScott Long if(acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 142144f05562SScott Long struct QBUFFER * prbuffer; 142244f05562SScott Long u_int8_t * iop_data; 1423ad6d6297SScott Long u_int32_t iop_len; 1424f1c579b1SScott Long 1425ad6d6297SScott Long acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 142644f05562SScott Long prbuffer=arcmsr_get_iop_rqbuffer(acb); 142744f05562SScott Long iop_data=(u_int8_t *)prbuffer->data; 1428ad6d6297SScott Long iop_len=(u_int32_t)prbuffer->data_len; 1429f1c579b1SScott Long /*this iop data does no chance to make me overflow again here, so just do it*/ 1430ad6d6297SScott Long while(iop_len>0) { 1431ad6d6297SScott Long pQbuffer= &acb->rqbuffer[acb->rqbuf_lastindex]; 1432f1c579b1SScott Long memcpy(pQbuffer, iop_data, 1); 1433ad6d6297SScott Long acb->rqbuf_lastindex++; 1434ad6d6297SScott Long acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; 1435ad6d6297SScott Long /*if last index number set it to 0 */ 1436f1c579b1SScott Long iop_data++; 1437f1c579b1SScott Long iop_len--; 1438f1c579b1SScott Long } 143944f05562SScott Long arcmsr_iop_message_read(acb); 144044f05562SScott Long /*signature, let IOP know data has been readed */ 1441f1c579b1SScott Long } 1442ad6d6297SScott Long pcmdmessagefld->cmdmessage.Length=allxfer_len; 1443ad6d6297SScott Long pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_OK; 1444ad6d6297SScott Long retvalue=ARCMSR_MESSAGE_SUCCESS; 1445f1c579b1SScott Long } 1446f1c579b1SScott Long break; 1447ad6d6297SScott Long case ARCMSR_MESSAGE_WRITE_WQBUFFER: { 1448ad6d6297SScott Long u_int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; 1449ad6d6297SScott Long u_int8_t * pQbuffer; 1450ad6d6297SScott Long u_int8_t * ptmpuserbuffer=pcmdmessagefld->messagedatabuffer; 1451f1c579b1SScott Long 1452ad6d6297SScott Long user_len=pcmdmessagefld->cmdmessage.Length; 1453f1c579b1SScott Long /*check if data xfer length of this request will overflow my array qbuffer */ 1454ad6d6297SScott Long wqbuf_lastindex=acb->wqbuf_lastindex; 1455ad6d6297SScott Long wqbuf_firstindex=acb->wqbuf_firstindex; 1456ad6d6297SScott Long if(wqbuf_lastindex!=wqbuf_firstindex) { 145744f05562SScott Long arcmsr_post_ioctldata2iop(acb); 1458ad6d6297SScott Long pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_ERROR; 1459ad6d6297SScott Long } else { 1460f1c579b1SScott Long my_empty_len=(wqbuf_firstindex-wqbuf_lastindex-1)&(ARCMSR_MAX_QBUFFER-1); 1461ad6d6297SScott Long if(my_empty_len>=user_len) { 1462ad6d6297SScott Long while(user_len>0) { 1463f1c579b1SScott Long /*copy srb data to wqbuffer*/ 1464ad6d6297SScott Long pQbuffer= &acb->wqbuffer[acb->wqbuf_lastindex]; 1465f1c579b1SScott Long memcpy(pQbuffer, ptmpuserbuffer, 1); 1466ad6d6297SScott Long acb->wqbuf_lastindex++; 1467ad6d6297SScott Long acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; 1468ad6d6297SScott Long /*if last index number set it to 0 */ 1469f1c579b1SScott Long ptmpuserbuffer++; 1470f1c579b1SScott Long user_len--; 1471f1c579b1SScott Long } 1472f1c579b1SScott Long /*post fist Qbuffer*/ 1473ad6d6297SScott Long if(acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { 1474ad6d6297SScott Long acb->acb_flags &=~ACB_F_MESSAGE_WQBUFFER_CLEARED; 147544f05562SScott Long arcmsr_post_ioctldata2iop(acb); 1476f1c579b1SScott Long } 1477ad6d6297SScott Long pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_OK; 1478ad6d6297SScott Long } else { 1479ad6d6297SScott Long pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_ERROR; 1480f1c579b1SScott Long } 1481f1c579b1SScott Long } 1482ad6d6297SScott Long retvalue=ARCMSR_MESSAGE_SUCCESS; 1483f1c579b1SScott Long } 1484f1c579b1SScott Long break; 1485ad6d6297SScott Long case ARCMSR_MESSAGE_CLEAR_RQBUFFER: { 1486ad6d6297SScott Long u_int8_t * pQbuffer=acb->rqbuffer; 1487ad6d6297SScott Long 1488ad6d6297SScott Long if(acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 1489ad6d6297SScott Long acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 149044f05562SScott Long arcmsr_iop_message_read(acb); 149144f05562SScott Long /*signature, let IOP know data has been readed */ 1492f1c579b1SScott Long } 1493ad6d6297SScott Long acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; 1494ad6d6297SScott Long acb->rqbuf_firstindex=0; 1495ad6d6297SScott Long acb->rqbuf_lastindex=0; 1496f1c579b1SScott Long memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); 1497ad6d6297SScott Long pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_OK; 1498ad6d6297SScott Long retvalue=ARCMSR_MESSAGE_SUCCESS; 1499f1c579b1SScott Long } 1500f1c579b1SScott Long break; 1501ad6d6297SScott Long case ARCMSR_MESSAGE_CLEAR_WQBUFFER: 1502f1c579b1SScott Long { 1503ad6d6297SScott Long u_int8_t * pQbuffer=acb->wqbuffer; 1504f1c579b1SScott Long 1505ad6d6297SScott Long if(acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 1506ad6d6297SScott Long acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 150744f05562SScott Long arcmsr_iop_message_read(acb); 150844f05562SScott Long /*signature, let IOP know data has been readed */ 1509f1c579b1SScott Long } 151044f05562SScott Long acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED|ACB_F_MESSAGE_WQBUFFER_READ); 1511ad6d6297SScott Long acb->wqbuf_firstindex=0; 1512ad6d6297SScott Long acb->wqbuf_lastindex=0; 1513f1c579b1SScott Long memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); 1514ad6d6297SScott Long pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_OK; 1515ad6d6297SScott Long retvalue=ARCMSR_MESSAGE_SUCCESS; 1516f1c579b1SScott Long } 1517f1c579b1SScott Long break; 1518ad6d6297SScott Long case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: { 1519ad6d6297SScott Long u_int8_t * pQbuffer; 1520f1c579b1SScott Long 1521ad6d6297SScott Long if(acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 1522ad6d6297SScott Long acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 152344f05562SScott Long arcmsr_iop_message_read(acb); 152444f05562SScott Long /*signature, let IOP know data has been readed */ 1525f1c579b1SScott Long } 1526ad6d6297SScott Long acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED 1527ad6d6297SScott Long |ACB_F_MESSAGE_RQBUFFER_CLEARED 152844f05562SScott Long |ACB_F_MESSAGE_WQBUFFER_READ); 1529ad6d6297SScott Long acb->rqbuf_firstindex=0; 1530ad6d6297SScott Long acb->rqbuf_lastindex=0; 1531ad6d6297SScott Long acb->wqbuf_firstindex=0; 1532ad6d6297SScott Long acb->wqbuf_lastindex=0; 1533ad6d6297SScott Long pQbuffer=acb->rqbuffer; 1534ad6d6297SScott Long memset(pQbuffer, 0, sizeof(struct QBUFFER)); 1535ad6d6297SScott Long pQbuffer=acb->wqbuffer; 1536ad6d6297SScott Long memset(pQbuffer, 0, sizeof(struct QBUFFER)); 1537ad6d6297SScott Long pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_OK; 1538ad6d6297SScott Long retvalue=ARCMSR_MESSAGE_SUCCESS; 1539f1c579b1SScott Long } 1540f1c579b1SScott Long break; 1541ad6d6297SScott Long case ARCMSR_MESSAGE_REQUEST_RETURNCODE_3F: { 1542ad6d6297SScott Long pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_3F; 1543ad6d6297SScott Long retvalue=ARCMSR_MESSAGE_SUCCESS; 1544f1c579b1SScott Long } 1545f1c579b1SScott Long break; 1546ad6d6297SScott Long case ARCMSR_MESSAGE_SAY_HELLO: { 1547ad6d6297SScott Long u_int8_t * hello_string="Hello! I am ARCMSR"; 1548ad6d6297SScott Long u_int8_t * puserbuffer=(u_int8_t *)pcmdmessagefld->messagedatabuffer; 1549f1c579b1SScott Long 1550ad6d6297SScott Long if(memcpy(puserbuffer, hello_string, (int16_t)strlen(hello_string))) { 1551ad6d6297SScott Long pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_ERROR; 1552ad6d6297SScott Long ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); 1553f1c579b1SScott Long return ENOIOCTL; 1554f1c579b1SScott Long } 1555ad6d6297SScott Long pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_OK; 1556ad6d6297SScott Long retvalue=ARCMSR_MESSAGE_SUCCESS; 1557ad6d6297SScott Long } 1558ad6d6297SScott Long break; 1559ad6d6297SScott Long case ARCMSR_MESSAGE_SAY_GOODBYE: { 1560ad6d6297SScott Long arcmsr_iop_parking(acb); 1561ad6d6297SScott Long retvalue=ARCMSR_MESSAGE_SUCCESS; 1562ad6d6297SScott Long } 1563ad6d6297SScott Long break; 1564ad6d6297SScott Long case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: { 1565ad6d6297SScott Long arcmsr_flush_adapter_cache(acb); 1566ad6d6297SScott Long retvalue=ARCMSR_MESSAGE_SUCCESS; 1567f1c579b1SScott Long } 1568f1c579b1SScott Long break; 1569f1c579b1SScott Long } 1570ad6d6297SScott Long ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); 1571ad6d6297SScott Long return retvalue; 1572f1c579b1SScott Long } 1573f1c579b1SScott Long /* 1574f1c579b1SScott Long ************************************************************************** 1575f1c579b1SScott Long ************************************************************************** 1576f1c579b1SScott Long */ 1577ad6d6297SScott Long struct CommandControlBlock * arcmsr_get_freesrb(struct AdapterControlBlock *acb) 1578f1c579b1SScott Long { 1579ad6d6297SScott Long struct CommandControlBlock *srb=NULL; 1580ad6d6297SScott Long u_int32_t workingsrb_startindex, workingsrb_doneindex; 1581f1c579b1SScott Long 1582579ec1a5SScott Long #if __FreeBSD_version < 700025 1583579ec1a5SScott Long ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); 1584579ec1a5SScott Long #endif 1585ad6d6297SScott Long workingsrb_doneindex=acb->workingsrb_doneindex; 1586ad6d6297SScott Long workingsrb_startindex=acb->workingsrb_startindex; 1587ad6d6297SScott Long srb=acb->srbworkingQ[workingsrb_startindex]; 1588ad6d6297SScott Long workingsrb_startindex++; 1589ad6d6297SScott Long workingsrb_startindex %= ARCMSR_MAX_FREESRB_NUM; 1590ad6d6297SScott Long if(workingsrb_doneindex!=workingsrb_startindex) { 1591ad6d6297SScott Long acb->workingsrb_startindex=workingsrb_startindex; 1592ad6d6297SScott Long } else { 1593ad6d6297SScott Long srb=NULL; 1594ad6d6297SScott Long } 1595579ec1a5SScott Long #if __FreeBSD_version < 700025 1596579ec1a5SScott Long ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); 1597579ec1a5SScott Long #endif 1598ad6d6297SScott Long return(srb); 1599ad6d6297SScott Long } 1600ad6d6297SScott Long /* 1601ad6d6297SScott Long ************************************************************************** 1602ad6d6297SScott Long ************************************************************************** 1603ad6d6297SScott Long */ 1604ad6d6297SScott Long static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, union ccb * pccb) 1605ad6d6297SScott Long { 1606ad6d6297SScott Long struct CMD_MESSAGE_FIELD * pcmdmessagefld; 1607ad6d6297SScott Long int retvalue = 0, transfer_len = 0; 1608ad6d6297SScott Long char *buffer; 160944f05562SScott Long u_int32_t controlcode = (u_int32_t ) pccb->csio.cdb_io.cdb_bytes[5] << 24 | 161044f05562SScott Long (u_int32_t ) pccb->csio.cdb_io.cdb_bytes[6] << 16 | 161144f05562SScott Long (u_int32_t ) pccb->csio.cdb_io.cdb_bytes[7] << 8 | 161244f05562SScott Long (u_int32_t ) pccb->csio.cdb_io.cdb_bytes[8]; 1613ad6d6297SScott Long /* 4 bytes: Areca io control code */ 1614ad6d6297SScott Long if((pccb->ccb_h.flags & CAM_SCATTER_VALID) == 0) { 1615ad6d6297SScott Long buffer = pccb->csio.data_ptr; 1616ad6d6297SScott Long transfer_len = pccb->csio.dxfer_len; 1617ad6d6297SScott Long } else { 1618ad6d6297SScott Long retvalue = ARCMSR_MESSAGE_FAIL; 1619ad6d6297SScott Long goto message_out; 1620ad6d6297SScott Long } 1621ad6d6297SScott Long if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) { 1622ad6d6297SScott Long retvalue = ARCMSR_MESSAGE_FAIL; 1623ad6d6297SScott Long goto message_out; 1624ad6d6297SScott Long } 1625ad6d6297SScott Long pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer; 1626ad6d6297SScott Long switch(controlcode) { 1627ad6d6297SScott Long case ARCMSR_MESSAGE_READ_RQBUFFER: { 1628ad6d6297SScott Long u_int8_t *pQbuffer; 1629ad6d6297SScott Long u_int8_t *ptmpQbuffer=pcmdmessagefld->messagedatabuffer; 1630ad6d6297SScott Long int32_t allxfer_len = 0; 1631f1c579b1SScott Long 1632ad6d6297SScott Long while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) 1633ad6d6297SScott Long && (allxfer_len < 1031)) { 1634ad6d6297SScott Long pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; 1635ad6d6297SScott Long memcpy(ptmpQbuffer, pQbuffer, 1); 1636ad6d6297SScott Long acb->rqbuf_firstindex++; 1637ad6d6297SScott Long acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; 1638ad6d6297SScott Long ptmpQbuffer++; 1639ad6d6297SScott Long allxfer_len++; 1640f1c579b1SScott Long } 1641ad6d6297SScott Long if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 164244f05562SScott Long struct QBUFFER *prbuffer; 164344f05562SScott Long u_int8_t *iop_data; 1644ad6d6297SScott Long int32_t iop_len; 1645ad6d6297SScott Long 1646ad6d6297SScott Long acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 164744f05562SScott Long prbuffer=arcmsr_get_iop_rqbuffer(acb); 164844f05562SScott Long iop_data = (u_int8_t *)prbuffer->data; 1649ad6d6297SScott Long iop_len =(u_int32_t)prbuffer->data_len; 1650ad6d6297SScott Long while (iop_len > 0) { 1651ad6d6297SScott Long pQbuffer= &acb->rqbuffer[acb->rqbuf_lastindex]; 1652ad6d6297SScott Long memcpy(pQbuffer, iop_data, 1); 1653ad6d6297SScott Long acb->rqbuf_lastindex++; 1654ad6d6297SScott Long acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; 1655ad6d6297SScott Long iop_data++; 1656ad6d6297SScott Long iop_len--; 1657f1c579b1SScott Long } 165844f05562SScott Long arcmsr_iop_message_read(acb); 1659ad6d6297SScott Long } 1660ad6d6297SScott Long pcmdmessagefld->cmdmessage.Length = allxfer_len; 1661ad6d6297SScott Long pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; 1662ad6d6297SScott Long retvalue=ARCMSR_MESSAGE_SUCCESS; 1663ad6d6297SScott Long } 1664ad6d6297SScott Long break; 1665ad6d6297SScott Long case ARCMSR_MESSAGE_WRITE_WQBUFFER: { 1666ad6d6297SScott Long int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; 1667ad6d6297SScott Long u_int8_t *pQbuffer; 1668ad6d6297SScott Long u_int8_t *ptmpuserbuffer=pcmdmessagefld->messagedatabuffer; 1669ad6d6297SScott Long 1670ad6d6297SScott Long user_len = pcmdmessagefld->cmdmessage.Length; 1671ad6d6297SScott Long wqbuf_lastindex = acb->wqbuf_lastindex; 1672ad6d6297SScott Long wqbuf_firstindex = acb->wqbuf_firstindex; 1673ad6d6297SScott Long if (wqbuf_lastindex != wqbuf_firstindex) { 167444f05562SScott Long arcmsr_post_ioctldata2iop(acb); 1675ad6d6297SScott Long /* has error report sensedata */ 1676ad6d6297SScott Long if(&pccb->csio.sense_data) { 1677ad6d6297SScott Long ((u_int8_t *)&pccb->csio.sense_data)[0] = (0x1 << 7 | 0x70); 1678ad6d6297SScott Long /* Valid,ErrorCode */ 1679ad6d6297SScott Long ((u_int8_t *)&pccb->csio.sense_data)[2] = 0x05; 1680ad6d6297SScott Long /* FileMark,EndOfMedia,IncorrectLength,Reserved,SenseKey */ 1681ad6d6297SScott Long ((u_int8_t *)&pccb->csio.sense_data)[7] = 0x0A; 1682ad6d6297SScott Long /* AdditionalSenseLength */ 1683ad6d6297SScott Long ((u_int8_t *)&pccb->csio.sense_data)[12] = 0x20; 1684ad6d6297SScott Long /* AdditionalSenseCode */ 1685ad6d6297SScott Long } 1686ad6d6297SScott Long retvalue = ARCMSR_MESSAGE_FAIL; 1687ad6d6297SScott Long } else { 1688ad6d6297SScott Long my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) 1689ad6d6297SScott Long &(ARCMSR_MAX_QBUFFER - 1); 1690ad6d6297SScott Long if (my_empty_len >= user_len) { 1691ad6d6297SScott Long while (user_len > 0) { 1692ad6d6297SScott Long pQbuffer = &acb->wqbuffer[acb->wqbuf_lastindex]; 1693ad6d6297SScott Long memcpy(pQbuffer, ptmpuserbuffer, 1); 1694ad6d6297SScott Long acb->wqbuf_lastindex++; 1695ad6d6297SScott Long acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; 1696ad6d6297SScott Long ptmpuserbuffer++; 1697ad6d6297SScott Long user_len--; 1698ad6d6297SScott Long } 1699ad6d6297SScott Long if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { 1700ad6d6297SScott Long acb->acb_flags &= 1701ad6d6297SScott Long ~ACB_F_MESSAGE_WQBUFFER_CLEARED; 170244f05562SScott Long arcmsr_post_ioctldata2iop(acb); 1703ad6d6297SScott Long } 1704ad6d6297SScott Long } else { 1705ad6d6297SScott Long /* has error report sensedata */ 1706ad6d6297SScott Long if(&pccb->csio.sense_data) { 1707ad6d6297SScott Long ((u_int8_t *)&pccb->csio.sense_data)[0] = (0x1 << 7 | 0x70); 1708ad6d6297SScott Long /* Valid,ErrorCode */ 1709ad6d6297SScott Long ((u_int8_t *)&pccb->csio.sense_data)[2] = 0x05; 1710ad6d6297SScott Long /* FileMark,EndOfMedia,IncorrectLength,Reserved,SenseKey */ 1711ad6d6297SScott Long ((u_int8_t *)&pccb->csio.sense_data)[7] = 0x0A; 1712ad6d6297SScott Long /* AdditionalSenseLength */ 1713ad6d6297SScott Long ((u_int8_t *)&pccb->csio.sense_data)[12] = 0x20; 1714ad6d6297SScott Long /* AdditionalSenseCode */ 1715ad6d6297SScott Long } 1716ad6d6297SScott Long retvalue = ARCMSR_MESSAGE_FAIL; 1717ad6d6297SScott Long } 1718ad6d6297SScott Long } 1719ad6d6297SScott Long } 1720ad6d6297SScott Long break; 1721ad6d6297SScott Long case ARCMSR_MESSAGE_CLEAR_RQBUFFER: { 1722ad6d6297SScott Long u_int8_t *pQbuffer = acb->rqbuffer; 1723ad6d6297SScott Long 1724ad6d6297SScott Long if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 1725ad6d6297SScott Long acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 172644f05562SScott Long arcmsr_iop_message_read(acb); 1727ad6d6297SScott Long } 1728ad6d6297SScott Long acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; 1729ad6d6297SScott Long acb->rqbuf_firstindex = 0; 1730ad6d6297SScott Long acb->rqbuf_lastindex = 0; 1731ad6d6297SScott Long memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); 1732ad6d6297SScott Long pcmdmessagefld->cmdmessage.ReturnCode = 1733ad6d6297SScott Long ARCMSR_MESSAGE_RETURNCODE_OK; 1734ad6d6297SScott Long } 1735ad6d6297SScott Long break; 1736ad6d6297SScott Long case ARCMSR_MESSAGE_CLEAR_WQBUFFER: { 1737ad6d6297SScott Long u_int8_t *pQbuffer = acb->wqbuffer; 1738ad6d6297SScott Long 1739ad6d6297SScott Long if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 1740ad6d6297SScott Long acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 174144f05562SScott Long arcmsr_iop_message_read(acb); 1742ad6d6297SScott Long } 1743ad6d6297SScott Long acb->acb_flags |= 1744ad6d6297SScott Long (ACB_F_MESSAGE_WQBUFFER_CLEARED | 174544f05562SScott Long ACB_F_MESSAGE_WQBUFFER_READ); 1746ad6d6297SScott Long acb->wqbuf_firstindex = 0; 1747ad6d6297SScott Long acb->wqbuf_lastindex = 0; 1748ad6d6297SScott Long memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); 1749ad6d6297SScott Long pcmdmessagefld->cmdmessage.ReturnCode = 1750ad6d6297SScott Long ARCMSR_MESSAGE_RETURNCODE_OK; 1751ad6d6297SScott Long } 1752ad6d6297SScott Long break; 1753ad6d6297SScott Long case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: { 1754ad6d6297SScott Long u_int8_t *pQbuffer; 1755ad6d6297SScott Long 1756ad6d6297SScott Long if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 1757ad6d6297SScott Long acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 175844f05562SScott Long arcmsr_iop_message_read(acb); 1759ad6d6297SScott Long } 1760ad6d6297SScott Long acb->acb_flags |= 1761ad6d6297SScott Long (ACB_F_MESSAGE_WQBUFFER_CLEARED 1762ad6d6297SScott Long | ACB_F_MESSAGE_RQBUFFER_CLEARED 176344f05562SScott Long | ACB_F_MESSAGE_WQBUFFER_READ); 1764ad6d6297SScott Long acb->rqbuf_firstindex = 0; 1765ad6d6297SScott Long acb->rqbuf_lastindex = 0; 1766ad6d6297SScott Long acb->wqbuf_firstindex = 0; 1767ad6d6297SScott Long acb->wqbuf_lastindex = 0; 1768ad6d6297SScott Long pQbuffer = acb->rqbuffer; 1769ad6d6297SScott Long memset(pQbuffer, 0, sizeof (struct QBUFFER)); 1770ad6d6297SScott Long pQbuffer = acb->wqbuffer; 1771ad6d6297SScott Long memset(pQbuffer, 0, sizeof (struct QBUFFER)); 1772ad6d6297SScott Long pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; 1773ad6d6297SScott Long } 1774ad6d6297SScott Long break; 1775ad6d6297SScott Long case ARCMSR_MESSAGE_REQUEST_RETURNCODE_3F: { 1776ad6d6297SScott Long pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F; 1777ad6d6297SScott Long } 1778ad6d6297SScott Long break; 1779ad6d6297SScott Long case ARCMSR_MESSAGE_SAY_HELLO: { 1780ad6d6297SScott Long int8_t * hello_string = "Hello! I am ARCMSR"; 1781ad6d6297SScott Long 1782ad6d6297SScott Long memcpy(pcmdmessagefld->messagedatabuffer, hello_string 1783ad6d6297SScott Long , (int16_t)strlen(hello_string)); 1784ad6d6297SScott Long pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; 1785ad6d6297SScott Long } 1786ad6d6297SScott Long break; 1787ad6d6297SScott Long case ARCMSR_MESSAGE_SAY_GOODBYE: 1788ad6d6297SScott Long arcmsr_iop_parking(acb); 1789ad6d6297SScott Long break; 1790ad6d6297SScott Long case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: 1791ad6d6297SScott Long arcmsr_flush_adapter_cache(acb); 1792ad6d6297SScott Long break; 1793ad6d6297SScott Long default: 1794ad6d6297SScott Long retvalue = ARCMSR_MESSAGE_FAIL; 1795ad6d6297SScott Long } 1796ad6d6297SScott Long message_out: 1797ad6d6297SScott Long return retvalue; 1798f1c579b1SScott Long } 1799f1c579b1SScott Long /* 1800f1c579b1SScott Long ********************************************************************* 1801f1c579b1SScott Long ********************************************************************* 1802f1c579b1SScott Long */ 1803ad6d6297SScott Long static void arcmsr_executesrb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 1804f1c579b1SScott Long { 1805ad6d6297SScott Long struct CommandControlBlock *srb=(struct CommandControlBlock *)arg; 1806ad6d6297SScott Long struct AdapterControlBlock *acb=(struct AdapterControlBlock *)srb->acb; 1807f1c579b1SScott Long union ccb * pccb; 1808ad6d6297SScott Long int target, lun; 1809f1c579b1SScott Long 1810ad6d6297SScott Long pccb=srb->pccb; 1811ad6d6297SScott Long target=pccb->ccb_h.target_id; 1812ad6d6297SScott Long lun=pccb->ccb_h.target_lun; 1813ad6d6297SScott Long if(error != 0) { 1814ad6d6297SScott Long if(error != EFBIG) { 181544f05562SScott Long printf("arcmsr%d: unexpected error %x" 181644f05562SScott Long " returned from 'bus_dmamap_load' \n" 1817ad6d6297SScott Long , acb->pci_unit, error); 1818f1c579b1SScott Long } 1819ad6d6297SScott Long if((pccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 182015735becSScott Long pccb->ccb_h.status |= CAM_REQ_TOO_BIG; 1821f1c579b1SScott Long } 1822ad6d6297SScott Long arcmsr_srb_complete(srb, 0); 1823f1c579b1SScott Long return; 1824f1c579b1SScott Long } 1825ad6d6297SScott Long if(nseg > ARCMSR_MAX_SG_ENTRIES) { 1826ad6d6297SScott Long pccb->ccb_h.status |= CAM_REQ_TOO_BIG; 1827ad6d6297SScott Long arcmsr_srb_complete(srb, 0); 1828ad6d6297SScott Long return; 1829f1c579b1SScott Long } 1830ad6d6297SScott Long if(acb->acb_flags & ACB_F_BUS_RESET) { 1831ad6d6297SScott Long printf("arcmsr%d: bus reset and return busy \n", acb->pci_unit); 1832ad6d6297SScott Long pccb->ccb_h.status |= CAM_SCSI_BUS_RESET; 1833ad6d6297SScott Long arcmsr_srb_complete(srb, 0); 1834ad6d6297SScott Long return; 1835ad6d6297SScott Long } 1836ad6d6297SScott Long if(acb->devstate[target][lun]==ARECA_RAID_GONE) { 1837ad6d6297SScott Long u_int8_t block_cmd; 1838ad6d6297SScott Long 1839ad6d6297SScott Long block_cmd=pccb->csio.cdb_io.cdb_bytes[0] & 0x0f; 1840ad6d6297SScott Long if(block_cmd==0x08 || block_cmd==0x0a) { 1841ad6d6297SScott Long printf("arcmsr%d:block 'read/write' command" 1842ad6d6297SScott Long "with gone raid volume Cmd=%2x, TargetId=%d, Lun=%d \n" 1843ad6d6297SScott Long , acb->pci_unit, block_cmd, target, lun); 1844ad6d6297SScott Long pccb->ccb_h.status |= CAM_DEV_NOT_THERE; 1845ad6d6297SScott Long arcmsr_srb_complete(srb, 0); 1846ad6d6297SScott Long return; 1847ad6d6297SScott Long } 1848ad6d6297SScott Long } 1849ad6d6297SScott Long if((pccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 1850ad6d6297SScott Long if(nseg != 0) { 1851ad6d6297SScott Long bus_dmamap_unload(acb->dm_segs_dmat, srb->dm_segs_dmamap); 1852ad6d6297SScott Long } 1853ad6d6297SScott Long arcmsr_srb_complete(srb, 0); 1854f1c579b1SScott Long return; 1855f1c579b1SScott Long } 1856ad6d6297SScott Long if(acb->srboutstandingcount >= ARCMSR_MAX_OUTSTANDING_CMD) { 185715735becSScott Long xpt_freeze_simq(acb->psim, 1); 185815735becSScott Long pccb->ccb_h.status = CAM_REQUEUE_REQ; 1859dc3a205bSScott Long acb->acb_flags |= ACB_F_CAM_DEV_QFRZN; 1860ad6d6297SScott Long arcmsr_srb_complete(srb, 0); 1861ad6d6297SScott Long return; 1862f1c579b1SScott Long } 186315735becSScott Long pccb->ccb_h.status |= CAM_SIM_QUEUED; 1864ad6d6297SScott Long arcmsr_build_srb(srb, dm_segs, nseg); 1865ad6d6297SScott Long arcmsr_post_srb(acb, srb); 1866f1c579b1SScott Long return; 1867f1c579b1SScott Long } 1868f1c579b1SScott Long /* 1869f1c579b1SScott Long ***************************************************************************************** 1870f1c579b1SScott Long ***************************************************************************************** 1871f1c579b1SScott Long */ 1872ad6d6297SScott Long static u_int8_t arcmsr_seek_cmd2abort(union ccb * abortccb) 1873f1c579b1SScott Long { 1874ad6d6297SScott Long struct CommandControlBlock *srb; 1875ad6d6297SScott Long struct AdapterControlBlock *acb=(struct AdapterControlBlock *) abortccb->ccb_h.arcmsr_ccbacb_ptr; 187644f05562SScott Long u_int32_t intmask_org; 1877ad6d6297SScott Long int i=0; 1878f1c579b1SScott Long 1879ad6d6297SScott Long acb->num_aborts++; 1880f1c579b1SScott Long /* 1881ad6d6297SScott Long *************************************************************************** 1882f1c579b1SScott Long ** It is the upper layer do abort command this lock just prior to calling us. 1883f1c579b1SScott Long ** First determine if we currently own this command. 1884f1c579b1SScott Long ** Start by searching the device queue. If not found 1885f1c579b1SScott Long ** at all, and the system wanted us to just abort the 1886f1c579b1SScott Long ** command return success. 1887ad6d6297SScott Long *************************************************************************** 1888f1c579b1SScott Long */ 1889ad6d6297SScott Long if(acb->srboutstandingcount!=0) { 1890ad6d6297SScott Long for(i=0;i<ARCMSR_MAX_FREESRB_NUM;i++) { 1891ad6d6297SScott Long srb=acb->psrb_pool[i]; 1892ad6d6297SScott Long if(srb->startdone==ARCMSR_SRB_START) { 1893ad6d6297SScott Long if(srb->pccb==abortccb) { 1894ad6d6297SScott Long srb->startdone=ARCMSR_SRB_ABORTED; 1895ad6d6297SScott Long printf("arcmsr%d:scsi id=%d lun=%d abort srb '%p'" 1896ad6d6297SScott Long "outstanding command \n" 1897ad6d6297SScott Long , acb->pci_unit, abortccb->ccb_h.target_id 1898ad6d6297SScott Long , abortccb->ccb_h.target_lun, srb); 1899ad6d6297SScott Long goto abort_outstanding_cmd; 1900f1c579b1SScott Long } 1901f1c579b1SScott Long } 1902f1c579b1SScott Long } 1903f1c579b1SScott Long } 1904f1c579b1SScott Long return(FALSE); 1905ad6d6297SScott Long abort_outstanding_cmd: 1906ad6d6297SScott Long /* disable all outbound interrupt */ 190744f05562SScott Long intmask_org=arcmsr_disable_allintr(acb); 1908ad6d6297SScott Long arcmsr_polling_srbdone(acb, srb); 190944f05562SScott Long /* enable outbound Post Queue, outbound doorbell Interrupt */ 191044f05562SScott Long arcmsr_enable_allintr(acb, intmask_org); 1911ad6d6297SScott Long return (TRUE); 1912f1c579b1SScott Long } 1913f1c579b1SScott Long /* 1914f1c579b1SScott Long **************************************************************************** 1915f1c579b1SScott Long **************************************************************************** 1916f1c579b1SScott Long */ 1917ad6d6297SScott Long static void arcmsr_bus_reset(struct AdapterControlBlock *acb) 1918f1c579b1SScott Long { 1919ad6d6297SScott Long int retry=0; 1920f1c579b1SScott Long 1921ad6d6297SScott Long acb->num_resets++; 1922ad6d6297SScott Long acb->acb_flags |=ACB_F_BUS_RESET; 1923ad6d6297SScott Long while(acb->srboutstandingcount!=0 && retry < 400) { 192444f05562SScott Long arcmsr_interrupt(acb); 1925ad6d6297SScott Long UDELAY(25000); 1926ad6d6297SScott Long retry++; 1927ad6d6297SScott Long } 1928ad6d6297SScott Long arcmsr_iop_reset(acb); 1929ad6d6297SScott Long acb->acb_flags &= ~ACB_F_BUS_RESET; 1930f1c579b1SScott Long return; 1931f1c579b1SScott Long } 1932f1c579b1SScott Long /* 1933ad6d6297SScott Long ************************************************************************** 1934ad6d6297SScott Long ************************************************************************** 1935ad6d6297SScott Long */ 1936ad6d6297SScott Long static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb, 1937ad6d6297SScott Long union ccb * pccb) 1938ad6d6297SScott Long { 1939ad6d6297SScott Long pccb->ccb_h.status |= CAM_REQ_CMP; 1940ad6d6297SScott Long switch (pccb->csio.cdb_io.cdb_bytes[0]) { 1941ad6d6297SScott Long case INQUIRY: { 1942ad6d6297SScott Long unsigned char inqdata[36]; 1943ad6d6297SScott Long char *buffer=pccb->csio.data_ptr;; 1944ad6d6297SScott Long 1945ad6d6297SScott Long if (pccb->ccb_h.target_lun) { 1946ad6d6297SScott Long pccb->ccb_h.status |= CAM_SEL_TIMEOUT; 1947ad6d6297SScott Long xpt_done(pccb); 1948ad6d6297SScott Long return; 1949ad6d6297SScott Long } 1950ad6d6297SScott Long inqdata[0] = T_PROCESSOR; 1951ad6d6297SScott Long /* Periph Qualifier & Periph Dev Type */ 1952ad6d6297SScott Long inqdata[1] = 0; 1953ad6d6297SScott Long /* rem media bit & Dev Type Modifier */ 1954ad6d6297SScott Long inqdata[2] = 0; 1955ad6d6297SScott Long /* ISO, ECMA, & ANSI versions */ 1956ad6d6297SScott Long inqdata[4] = 31; 1957ad6d6297SScott Long /* length of additional data */ 1958ad6d6297SScott Long strncpy(&inqdata[8], "Areca ", 8); 1959ad6d6297SScott Long /* Vendor Identification */ 1960ad6d6297SScott Long strncpy(&inqdata[16], "RAID controller ", 16); 1961ad6d6297SScott Long /* Product Identification */ 1962ad6d6297SScott Long strncpy(&inqdata[32], "R001", 4); /* Product Revision */ 1963ad6d6297SScott Long memcpy(buffer, inqdata, sizeof(inqdata)); 1964ad6d6297SScott Long xpt_done(pccb); 1965ad6d6297SScott Long } 1966ad6d6297SScott Long break; 1967ad6d6297SScott Long case WRITE_BUFFER: 1968ad6d6297SScott Long case READ_BUFFER: { 1969ad6d6297SScott Long if (arcmsr_iop_message_xfer(acb, pccb)) { 1970ad6d6297SScott Long pccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 1971ad6d6297SScott Long pccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 1972ad6d6297SScott Long } 1973ad6d6297SScott Long xpt_done(pccb); 1974ad6d6297SScott Long } 1975ad6d6297SScott Long break; 1976ad6d6297SScott Long default: 1977ad6d6297SScott Long xpt_done(pccb); 1978ad6d6297SScott Long } 1979ad6d6297SScott Long } 1980ad6d6297SScott Long /* 1981f1c579b1SScott Long ********************************************************************* 1982f1c579b1SScott Long ********************************************************************* 1983f1c579b1SScott Long */ 1984ad6d6297SScott Long static void arcmsr_action(struct cam_sim * psim, union ccb * pccb) 1985f1c579b1SScott Long { 1986ad6d6297SScott Long struct AdapterControlBlock * acb; 1987f1c579b1SScott Long 1988ad6d6297SScott Long acb=(struct AdapterControlBlock *) cam_sim_softc(psim); 1989ad6d6297SScott Long if(acb==NULL) { 1990ad6d6297SScott Long pccb->ccb_h.status |= CAM_REQ_INVALID; 1991f1c579b1SScott Long xpt_done(pccb); 1992f1c579b1SScott Long return; 1993f1c579b1SScott Long } 1994ad6d6297SScott Long switch (pccb->ccb_h.func_code) { 1995ad6d6297SScott Long case XPT_SCSI_IO: { 1996ad6d6297SScott Long struct CommandControlBlock *srb; 1997ad6d6297SScott Long int target=pccb->ccb_h.target_id; 1998f1c579b1SScott Long 1999ad6d6297SScott Long if(target == 16) { 2000ad6d6297SScott Long /* virtual device for iop message transfer */ 2001ad6d6297SScott Long arcmsr_handle_virtual_command(acb, pccb); 2002ad6d6297SScott Long return; 2003ad6d6297SScott Long } 2004ad6d6297SScott Long if((srb=arcmsr_get_freesrb(acb)) == NULL) { 2005ad6d6297SScott Long pccb->ccb_h.status |= CAM_RESRC_UNAVAIL; 2006f1c579b1SScott Long xpt_done(pccb); 2007f1c579b1SScott Long return; 2008f1c579b1SScott Long } 2009ad6d6297SScott Long pccb->ccb_h.arcmsr_ccbsrb_ptr=srb; 2010ad6d6297SScott Long pccb->ccb_h.arcmsr_ccbacb_ptr=acb; 2011ad6d6297SScott Long srb->pccb=pccb; 2012ad6d6297SScott Long if((pccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 2013ad6d6297SScott Long if(!(pccb->ccb_h.flags & CAM_SCATTER_VALID)) { 2014ad6d6297SScott Long /* Single buffer */ 2015ad6d6297SScott Long if(!(pccb->ccb_h.flags & CAM_DATA_PHYS)) { 2016ad6d6297SScott Long /* Buffer is virtual */ 2017ad6d6297SScott Long u_int32_t error, s; 2018f1c579b1SScott Long 2019f1c579b1SScott Long s=splsoftvm(); 2020ad6d6297SScott Long error = bus_dmamap_load(acb->dm_segs_dmat 2021ad6d6297SScott Long , srb->dm_segs_dmamap 2022ad6d6297SScott Long , pccb->csio.data_ptr 2023ad6d6297SScott Long , pccb->csio.dxfer_len 2024ad6d6297SScott Long , arcmsr_executesrb, srb, /*flags*/0); 2025ad6d6297SScott Long if(error == EINPROGRESS) { 2026ad6d6297SScott Long xpt_freeze_simq(acb->psim, 1); 2027f1c579b1SScott Long pccb->ccb_h.status |= CAM_RELEASE_SIMQ; 2028f1c579b1SScott Long } 2029f1c579b1SScott Long splx(s); 2030ad6d6297SScott Long } else { 2031ad6d6297SScott Long /* Buffer is physical */ 20321c7e9358SScott Long panic("arcmsr: CAM_DATA_PHYS not supported"); 2033f1c579b1SScott Long } 2034ad6d6297SScott Long } else { 2035ad6d6297SScott Long /* Scatter/gather list */ 2036f1c579b1SScott Long struct bus_dma_segment *segs; 2037f1c579b1SScott Long 2038ad6d6297SScott Long if((pccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0 2039ad6d6297SScott Long || (pccb->ccb_h.flags & CAM_DATA_PHYS) != 0) { 2040ad6d6297SScott Long pccb->ccb_h.status |= CAM_PROVIDE_FAIL; 2041f1c579b1SScott Long xpt_done(pccb); 2042ad6d6297SScott Long free(srb, M_DEVBUF); 2043f1c579b1SScott Long return; 2044f1c579b1SScott Long } 2045f1c579b1SScott Long segs=(struct bus_dma_segment *)pccb->csio.data_ptr; 2046ad6d6297SScott Long arcmsr_executesrb(srb, segs, pccb->csio.sglist_cnt, 0); 2047f1c579b1SScott Long } 2048ad6d6297SScott Long } else { 2049ad6d6297SScott Long arcmsr_executesrb(srb, NULL, 0, 0); 2050f1c579b1SScott Long } 2051f1c579b1SScott Long break; 2052f1c579b1SScott Long } 2053ad6d6297SScott Long case XPT_TARGET_IO: { 2054ad6d6297SScott Long /* target mode not yet support vendor specific commands. */ 2055ad6d6297SScott Long pccb->ccb_h.status |= CAM_REQ_CMP; 2056f1c579b1SScott Long xpt_done(pccb); 2057f1c579b1SScott Long break; 2058f1c579b1SScott Long } 2059ad6d6297SScott Long case XPT_PATH_INQ: { 2060f1c579b1SScott Long struct ccb_pathinq *cpi= &pccb->cpi; 2061f1c579b1SScott Long 2062f1c579b1SScott Long cpi->version_num=1; 2063f1c579b1SScott Long cpi->hba_inquiry=PI_SDTR_ABLE | PI_TAG_ABLE; 2064f1c579b1SScott Long cpi->target_sprt=0; 2065f1c579b1SScott Long cpi->hba_misc=0; 2066f1c579b1SScott Long cpi->hba_eng_cnt=0; 2067ad6d6297SScott Long cpi->max_target=ARCMSR_MAX_TARGETID; /* 0-16 */ 2068ad6d6297SScott Long cpi->max_lun=ARCMSR_MAX_TARGETLUN; /* 0-7 */ 2069ad6d6297SScott Long cpi->initiator_id=ARCMSR_SCSI_INITIATOR_ID; /* 255 */ 2070f1c579b1SScott Long cpi->bus_id=cam_sim_bus(psim); 2071f1c579b1SScott Long strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 2072f1c579b1SScott Long strncpy(cpi->hba_vid, "ARCMSR", HBA_IDLEN); 2073f1c579b1SScott Long strncpy(cpi->dev_name, cam_sim_name(psim), DEV_IDLEN); 2074f1c579b1SScott Long cpi->unit_number=cam_sim_unit(psim); 207544f05562SScott Long #ifdef CAM_NEW_TRAN_CODE 2076fa9ed865SMatt Jacob cpi->transport = XPORT_SPI; 2077fa9ed865SMatt Jacob cpi->transport_version = 2; 2078fa9ed865SMatt Jacob cpi->protocol = PROTO_SCSI; 2079fa9ed865SMatt Jacob cpi->protocol_version = SCSI_REV_2; 208044f05562SScott Long #endif 2081ad6d6297SScott Long cpi->ccb_h.status |= CAM_REQ_CMP; 2082f1c579b1SScott Long xpt_done(pccb); 2083f1c579b1SScott Long break; 2084f1c579b1SScott Long } 2085ad6d6297SScott Long case XPT_ABORT: { 2086f1c579b1SScott Long union ccb *pabort_ccb; 2087f1c579b1SScott Long 2088f1c579b1SScott Long pabort_ccb=pccb->cab.abort_ccb; 2089ad6d6297SScott Long switch (pabort_ccb->ccb_h.func_code) { 2090f1c579b1SScott Long case XPT_ACCEPT_TARGET_IO: 2091f1c579b1SScott Long case XPT_IMMED_NOTIFY: 2092f1c579b1SScott Long case XPT_CONT_TARGET_IO: 2093ad6d6297SScott Long if(arcmsr_seek_cmd2abort(pabort_ccb)==TRUE) { 2094ad6d6297SScott Long pabort_ccb->ccb_h.status |= CAM_REQ_ABORTED; 2095f1c579b1SScott Long xpt_done(pabort_ccb); 2096ad6d6297SScott Long pccb->ccb_h.status |= CAM_REQ_CMP; 2097ad6d6297SScott Long } else { 2098f1c579b1SScott Long xpt_print_path(pabort_ccb->ccb_h.path); 2099f1c579b1SScott Long printf("Not found\n"); 2100ad6d6297SScott Long pccb->ccb_h.status |= CAM_PATH_INVALID; 2101f1c579b1SScott Long } 2102f1c579b1SScott Long break; 2103f1c579b1SScott Long case XPT_SCSI_IO: 2104ad6d6297SScott Long pccb->ccb_h.status |= CAM_UA_ABORT; 2105f1c579b1SScott Long break; 2106f1c579b1SScott Long default: 2107ad6d6297SScott Long pccb->ccb_h.status |= CAM_REQ_INVALID; 2108f1c579b1SScott Long break; 2109f1c579b1SScott Long } 2110f1c579b1SScott Long xpt_done(pccb); 2111f1c579b1SScott Long break; 2112f1c579b1SScott Long } 2113f1c579b1SScott Long case XPT_RESET_BUS: 2114ad6d6297SScott Long case XPT_RESET_DEV: { 2115ad6d6297SScott Long u_int32_t i; 2116f1c579b1SScott Long 2117ad6d6297SScott Long arcmsr_bus_reset(acb); 2118ad6d6297SScott Long for (i=0; i < 500; i++) { 2119f1c579b1SScott Long DELAY(1000); 2120f1c579b1SScott Long } 2121ad6d6297SScott Long pccb->ccb_h.status |= CAM_REQ_CMP; 2122f1c579b1SScott Long xpt_done(pccb); 2123f1c579b1SScott Long break; 2124f1c579b1SScott Long } 2125ad6d6297SScott Long case XPT_TERM_IO: { 2126ad6d6297SScott Long pccb->ccb_h.status |= CAM_REQ_INVALID; 2127f1c579b1SScott Long xpt_done(pccb); 2128f1c579b1SScott Long break; 2129f1c579b1SScott Long } 2130ad6d6297SScott Long case XPT_GET_TRAN_SETTINGS: { 2131ad6d6297SScott Long struct ccb_trans_settings *cts; 2132ad6d6297SScott Long 2133ad6d6297SScott Long if(pccb->ccb_h.target_id == 16) { 2134ad6d6297SScott Long pccb->ccb_h.status |= CAM_FUNC_NOTAVAIL; 2135ad6d6297SScott Long xpt_done(pccb); 2136ad6d6297SScott Long break; 2137ad6d6297SScott Long } 2138ad6d6297SScott Long cts= &pccb->cts; 213944f05562SScott Long #ifdef CAM_NEW_TRAN_CODE 214044f05562SScott Long { 214144f05562SScott Long struct ccb_trans_settings_scsi *scsi; 214244f05562SScott Long struct ccb_trans_settings_spi *spi; 214344f05562SScott Long 2144ad6d6297SScott Long scsi = &cts->proto_specific.scsi; 2145ad6d6297SScott Long spi = &cts->xport_specific.spi; 2146fa9ed865SMatt Jacob cts->protocol = PROTO_SCSI; 2147fa9ed865SMatt Jacob cts->protocol_version = SCSI_REV_2; 2148fa9ed865SMatt Jacob cts->transport = XPORT_SPI; 2149fa9ed865SMatt Jacob cts->transport_version = 2; 2150fa9ed865SMatt Jacob spi->flags = CTS_SPI_FLAGS_DISC_ENB; 2151fa9ed865SMatt Jacob spi->sync_period=3; 2152fa9ed865SMatt Jacob spi->sync_offset=32; 2153fa9ed865SMatt Jacob spi->bus_width=MSG_EXT_WDTR_BUS_16_BIT; 2154fa9ed865SMatt Jacob scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 21559d98ff4dSScott Long spi->valid = CTS_SPI_VALID_DISC 21569d98ff4dSScott Long | CTS_SPI_VALID_SYNC_RATE 2157fa9ed865SMatt Jacob | CTS_SPI_VALID_SYNC_OFFSET 2158fa9ed865SMatt Jacob | CTS_SPI_VALID_BUS_WIDTH; 2159fa9ed865SMatt Jacob scsi->valid = CTS_SCSI_VALID_TQ; 216044f05562SScott Long } 216144f05562SScott Long #else 216244f05562SScott Long { 216344f05562SScott Long cts->flags=(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB); 216444f05562SScott Long cts->sync_period=3; 216544f05562SScott Long cts->sync_offset=32; 216644f05562SScott Long cts->bus_width=MSG_EXT_WDTR_BUS_16_BIT; 216744f05562SScott Long cts->valid=CCB_TRANS_SYNC_RATE_VALID | 216844f05562SScott Long CCB_TRANS_SYNC_OFFSET_VALID | 216944f05562SScott Long CCB_TRANS_BUS_WIDTH_VALID | 217044f05562SScott Long CCB_TRANS_DISC_VALID | 217144f05562SScott Long CCB_TRANS_TQ_VALID; 217244f05562SScott Long } 217344f05562SScott Long #endif 2174ad6d6297SScott Long pccb->ccb_h.status |= CAM_REQ_CMP; 2175ad6d6297SScott Long xpt_done(pccb); 2176ad6d6297SScott Long break; 2177ad6d6297SScott Long } 2178ad6d6297SScott Long case XPT_SET_TRAN_SETTINGS: { 2179ad6d6297SScott Long pccb->ccb_h.status |= CAM_FUNC_NOTAVAIL; 2180ad6d6297SScott Long xpt_done(pccb); 2181ad6d6297SScott Long break; 2182ad6d6297SScott Long } 2183ad6d6297SScott Long case XPT_CALC_GEOMETRY: { 2184ad6d6297SScott Long struct ccb_calc_geometry *ccg; 2185ad6d6297SScott Long u_int32_t size_mb; 2186ad6d6297SScott Long u_int32_t secs_per_cylinder; 2187ad6d6297SScott Long 2188ad6d6297SScott Long if(pccb->ccb_h.target_id == 16) { 2189ad6d6297SScott Long pccb->ccb_h.status |= CAM_FUNC_NOTAVAIL; 2190ad6d6297SScott Long xpt_done(pccb); 2191ad6d6297SScott Long break; 2192ad6d6297SScott Long } 2193f1c579b1SScott Long ccg= &pccb->ccg; 2194ad6d6297SScott Long if (ccg->block_size == 0) { 2195ad6d6297SScott Long pccb->ccb_h.status = CAM_REQ_INVALID; 2196ad6d6297SScott Long xpt_done(pccb); 2197ad6d6297SScott Long break; 2198ad6d6297SScott Long } 2199ad6d6297SScott Long if(((1024L * 1024L)/ccg->block_size) < 0) { 2200ad6d6297SScott Long pccb->ccb_h.status = CAM_REQ_INVALID; 2201ad6d6297SScott Long xpt_done(pccb); 2202ad6d6297SScott Long break; 2203ad6d6297SScott Long } 2204f1c579b1SScott Long size_mb=ccg->volume_size/((1024L * 1024L)/ccg->block_size); 2205ad6d6297SScott Long if(size_mb > 1024 ) { 2206f1c579b1SScott Long ccg->heads=255; 2207f1c579b1SScott Long ccg->secs_per_track=63; 2208ad6d6297SScott Long } else { 2209f1c579b1SScott Long ccg->heads=64; 2210f1c579b1SScott Long ccg->secs_per_track=32; 2211f1c579b1SScott Long } 2212f1c579b1SScott Long secs_per_cylinder=ccg->heads * ccg->secs_per_track; 2213f1c579b1SScott Long ccg->cylinders=ccg->volume_size / secs_per_cylinder; 2214ad6d6297SScott Long pccb->ccb_h.status |= CAM_REQ_CMP; 2215f1c579b1SScott Long xpt_done(pccb); 2216f1c579b1SScott Long break; 2217f1c579b1SScott Long } 2218f1c579b1SScott Long default: 2219ad6d6297SScott Long pccb->ccb_h.status |= CAM_REQ_INVALID; 2220f1c579b1SScott Long xpt_done(pccb); 2221f1c579b1SScott Long break; 2222f1c579b1SScott Long } 2223f1c579b1SScott Long return; 2224f1c579b1SScott Long } 2225f1c579b1SScott Long /* 2226f1c579b1SScott Long ********************************************************************** 2227f1c579b1SScott Long ********************************************************************** 2228f1c579b1SScott Long */ 222944f05562SScott Long static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb) 2230f1c579b1SScott Long { 2231ad6d6297SScott Long acb->acb_flags |= ACB_F_MSG_START_BGRB; 223244f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_START_BGRB); 223344f05562SScott Long if(!arcmsr_hba_wait_msgint_ready(acb)) { 2234ad6d6297SScott Long printf("arcmsr%d: wait 'start adapter background rebulid' timeout \n", acb->pci_unit); 2235ad6d6297SScott Long } 2236f1c579b1SScott Long return; 2237f1c579b1SScott Long } 2238f1c579b1SScott Long /* 2239f1c579b1SScott Long ********************************************************************** 2240f1c579b1SScott Long ********************************************************************** 2241f1c579b1SScott Long */ 224244f05562SScott Long static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb) 224344f05562SScott Long { 224444f05562SScott Long acb->acb_flags |= ACB_F_MSG_START_BGRB; 224544f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 224644f05562SScott Long 0, drv2iop_doorbell, ARCMSR_MESSAGE_START_BGRB); 224744f05562SScott Long if(!arcmsr_hbb_wait_msgint_ready(acb)) { 224844f05562SScott Long printf( "arcmsr%d: wait 'start adapter background rebulid' timeout \n", acb->pci_unit); 224944f05562SScott Long } 225044f05562SScott Long return; 225144f05562SScott Long } 225244f05562SScott Long /* 225344f05562SScott Long ********************************************************************** 225444f05562SScott Long ********************************************************************** 225544f05562SScott Long */ 225644f05562SScott Long static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb) 225744f05562SScott Long { 225844f05562SScott Long switch (acb->adapter_type) { 225944f05562SScott Long case ACB_ADAPTER_TYPE_A: 226044f05562SScott Long arcmsr_start_hba_bgrb(acb); 226144f05562SScott Long break; 226244f05562SScott Long case ACB_ADAPTER_TYPE_B: 226344f05562SScott Long arcmsr_start_hbb_bgrb(acb); 226444f05562SScott Long break; 226544f05562SScott Long } 226644f05562SScott Long return; 226744f05562SScott Long } 226844f05562SScott Long /* 226944f05562SScott Long ********************************************************************** 227044f05562SScott Long ** 227144f05562SScott Long ********************************************************************** 227244f05562SScott Long */ 227344f05562SScott Long static void arcmsr_polling_hba_srbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_srb) 2274f1c579b1SScott Long { 2275ad6d6297SScott Long struct CommandControlBlock *srb; 227644f05562SScott Long u_int32_t flag_srb, outbound_intstatus, poll_srb_done=0, poll_count=0; 2277f1c579b1SScott Long 227844f05562SScott Long polling_ccb_retry: 2279ad6d6297SScott Long poll_count++; 228044f05562SScott Long outbound_intstatus=CHIP_REG_READ32(HBA_MessageUnit, 228144f05562SScott Long 0, outbound_intstatus) & acb->outbound_int_enable; 228244f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 228344f05562SScott Long 0, outbound_intstatus, outbound_intstatus);/*clear interrupt*/ 228444f05562SScott Long bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 2285ad6d6297SScott Long while(1) { 228644f05562SScott Long if((flag_srb=CHIP_REG_READ32(HBA_MessageUnit, 228744f05562SScott Long 0, outbound_queueport))==0xFFFFFFFF) { 2288ad6d6297SScott Long if(poll_srb_done) { 2289ad6d6297SScott Long break;/*chip FIFO no ccb for completion already*/ 2290ad6d6297SScott Long } else { 2291ad6d6297SScott Long UDELAY(25000); 2292ad6d6297SScott Long if(poll_count > 100) { 2293ad6d6297SScott Long break; 2294f1c579b1SScott Long } 229544f05562SScott Long goto polling_ccb_retry; 2296f1c579b1SScott Long } 2297ad6d6297SScott Long } 2298ad6d6297SScott Long /* check ifcommand done with no error*/ 229944f05562SScott Long srb=(struct CommandControlBlock *) 230044f05562SScott Long (acb->vir2phy_offset+(flag_srb << 5));/*frame must be 32 bytes aligned*/ 230144f05562SScott Long poll_srb_done = (srb==poll_srb) ? 1:0; 2302ad6d6297SScott Long if((srb->acb!=acb) || (srb->startdone!=ARCMSR_SRB_START)) { 230344f05562SScott Long if(srb->startdone==ARCMSR_SRB_ABORTED) { 2304ad6d6297SScott Long printf("arcmsr%d: scsi id=%d lun=%d srb='%p'" 2305ad6d6297SScott Long "poll command abort successfully \n" 2306ad6d6297SScott Long , acb->pci_unit 2307ad6d6297SScott Long , srb->pccb->ccb_h.target_id 2308ad6d6297SScott Long , srb->pccb->ccb_h.target_lun, srb); 2309ad6d6297SScott Long srb->pccb->ccb_h.status |= CAM_REQ_ABORTED; 2310ad6d6297SScott Long arcmsr_srb_complete(srb, 1); 2311ad6d6297SScott Long continue; 2312ad6d6297SScott Long } 2313ad6d6297SScott Long printf("arcmsr%d: polling get an illegal srb command done srb='%p'" 2314ad6d6297SScott Long "srboutstandingcount=%d \n" 2315ad6d6297SScott Long , acb->pci_unit 2316ad6d6297SScott Long , srb, acb->srboutstandingcount); 2317ad6d6297SScott Long continue; 2318ad6d6297SScott Long } 231944f05562SScott Long arcmsr_report_srb_state(acb, srb, flag_srb); 2320ad6d6297SScott Long } /*drain reply FIFO*/ 2321f1c579b1SScott Long return; 2322f1c579b1SScott Long } 2323f1c579b1SScott Long /* 2324f1c579b1SScott Long ********************************************************************** 232544f05562SScott Long ** 2326ad6d6297SScott Long ********************************************************************** 2327ad6d6297SScott Long */ 232844f05562SScott Long static void arcmsr_polling_hbb_srbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_srb) 232944f05562SScott Long { 233044f05562SScott Long struct HBB_MessageUnit *phbbmu=(struct HBB_MessageUnit *)acb->pmu; 233144f05562SScott Long struct CommandControlBlock *srb; 233244f05562SScott Long u_int32_t flag_srb, poll_srb_done=0, poll_count=0; 233344f05562SScott Long int index; 233444f05562SScott Long 233544f05562SScott Long polling_ccb_retry: 233644f05562SScott Long poll_count++; 233744f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 233844f05562SScott Long 0, iop2drv_doorbell, ARCMSR_DOORBELL_INT_CLEAR_PATTERN); /* clear doorbell interrupt */ 233944f05562SScott Long bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 234044f05562SScott Long while(1) { 234144f05562SScott Long index=phbbmu->doneq_index; 234244f05562SScott Long if((flag_srb=phbbmu->done_qbuffer[index]) == 0) { 234344f05562SScott Long if(poll_srb_done) { 234444f05562SScott Long break;/*chip FIFO no ccb for completion already*/ 234544f05562SScott Long } else { 234644f05562SScott Long UDELAY(25000); 234744f05562SScott Long if(poll_count > 100) { 234844f05562SScott Long break; 234944f05562SScott Long } 235044f05562SScott Long goto polling_ccb_retry; 235144f05562SScott Long } 235244f05562SScott Long } 235344f05562SScott Long phbbmu->done_qbuffer[index]=0; 235444f05562SScott Long index++; 235544f05562SScott Long index %= ARCMSR_MAX_HBB_POSTQUEUE; /*if last index number set it to 0 */ 235644f05562SScott Long phbbmu->doneq_index=index; 235744f05562SScott Long /* check if command done with no error*/ 235844f05562SScott Long srb=(struct CommandControlBlock *) 235944f05562SScott Long (acb->vir2phy_offset+(flag_srb << 5));/*frame must be 32 bytes aligned*/ 236044f05562SScott Long poll_srb_done = (srb==poll_srb) ? 1:0; 236144f05562SScott Long if((srb->acb!=acb) || (srb->startdone!=ARCMSR_SRB_START)) { 236244f05562SScott Long if(srb->startdone==ARCMSR_SRB_ABORTED) { 236344f05562SScott Long printf("arcmsr%d: scsi id=%d lun=%d srb='%p'" 236444f05562SScott Long "poll command abort successfully \n" 236544f05562SScott Long , acb->pci_unit 236644f05562SScott Long , srb->pccb->ccb_h.target_id 236744f05562SScott Long , srb->pccb->ccb_h.target_lun, srb); 236844f05562SScott Long srb->pccb->ccb_h.status |= CAM_REQ_ABORTED; 236944f05562SScott Long arcmsr_srb_complete(srb, 1); 237044f05562SScott Long continue; 237144f05562SScott Long } 237244f05562SScott Long printf("arcmsr%d: polling get an illegal srb command done srb='%p'" 237344f05562SScott Long "srboutstandingcount=%d \n" 237444f05562SScott Long , acb->pci_unit 237544f05562SScott Long , srb, acb->srboutstandingcount); 237644f05562SScott Long continue; 237744f05562SScott Long } 237844f05562SScott Long arcmsr_report_srb_state(acb, srb, flag_srb); 237944f05562SScott Long } /*drain reply FIFO*/ 238044f05562SScott Long return; 238144f05562SScott Long } 238244f05562SScott Long /* 238344f05562SScott Long ********************************************************************** 238444f05562SScott Long ********************************************************************** 238544f05562SScott Long */ 238644f05562SScott Long static void arcmsr_polling_srbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_srb) 238744f05562SScott Long { 238844f05562SScott Long switch (acb->adapter_type) { 238944f05562SScott Long case ACB_ADAPTER_TYPE_A: { 239044f05562SScott Long arcmsr_polling_hba_srbdone(acb, poll_srb); 239144f05562SScott Long } 239244f05562SScott Long break; 239344f05562SScott Long case ACB_ADAPTER_TYPE_B: { 239444f05562SScott Long arcmsr_polling_hbb_srbdone(acb, poll_srb); 239544f05562SScott Long } 239644f05562SScott Long break; 239744f05562SScott Long } 239844f05562SScott Long } 239944f05562SScott Long /* 240044f05562SScott Long ********************************************************************** 240144f05562SScott Long ********************************************************************** 240244f05562SScott Long */ 240344f05562SScott Long static void arcmsr_get_hba_config(struct AdapterControlBlock *acb) 2404ad6d6297SScott Long { 2405ad6d6297SScott Long char *acb_firm_model=acb->firm_model; 2406ad6d6297SScott Long char *acb_firm_version=acb->firm_version; 240744f05562SScott Long size_t iop_firm_model=offsetof(struct HBA_MessageUnit,msgcode_rwbuffer[15]); /*firm_model,15,60-67*/ 240844f05562SScott Long size_t iop_firm_version=offsetof(struct HBA_MessageUnit,msgcode_rwbuffer[17]); /*firm_version,17,68-83*/ 2409ad6d6297SScott Long int i; 2410ad6d6297SScott Long 241144f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG); 241244f05562SScott Long if(!arcmsr_hba_wait_msgint_ready(acb)) { 2413ad6d6297SScott Long printf("arcmsr%d: wait 'get adapter firmware miscellaneous data' timeout \n" 2414ad6d6297SScott Long , acb->pci_unit); 2415ad6d6297SScott Long } 2416ad6d6297SScott Long i=0; 2417ad6d6297SScott Long while(i<8) { 241844f05562SScott Long *acb_firm_model=bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_firm_model+i); 2419ad6d6297SScott Long /* 8 bytes firm_model, 15, 60-67*/ 2420ad6d6297SScott Long acb_firm_model++; 2421ad6d6297SScott Long i++; 2422ad6d6297SScott Long } 2423ad6d6297SScott Long i=0; 2424ad6d6297SScott Long while(i<16) { 242544f05562SScott Long *acb_firm_version=bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_firm_version+i); 2426ad6d6297SScott Long /* 16 bytes firm_version, 17, 68-83*/ 2427ad6d6297SScott Long acb_firm_version++; 2428ad6d6297SScott Long i++; 2429ad6d6297SScott Long } 2430ad6d6297SScott Long printf("ARECA RAID ADAPTER%d: %s \n", acb->pci_unit, ARCMSR_DRIVER_VERSION); 2431ad6d6297SScott Long printf("ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n", acb->pci_unit, acb->firm_version); 243244f05562SScott Long acb->firm_request_len=CHIP_REG_READ32(HBA_MessageUnit, 243344f05562SScott Long 0, msgcode_rwbuffer[1]); /*firm_request_len, 1, 04-07*/ 243444f05562SScott Long acb->firm_numbers_queue=CHIP_REG_READ32(HBA_MessageUnit, 243544f05562SScott Long 0, msgcode_rwbuffer[2]); /*firm_numbers_queue, 2, 08-11*/ 243644f05562SScott Long acb->firm_sdram_size=CHIP_REG_READ32(HBA_MessageUnit, 243744f05562SScott Long 0, msgcode_rwbuffer[3]); /*firm_sdram_size, 3, 12-15*/ 243844f05562SScott Long acb->firm_ide_channels=CHIP_REG_READ32(HBA_MessageUnit, 243944f05562SScott Long 0, msgcode_rwbuffer[4]); /*firm_ide_channels, 4, 16-19*/ 2440ad6d6297SScott Long return; 2441ad6d6297SScott Long } 2442ad6d6297SScott Long /* 2443ad6d6297SScott Long ********************************************************************** 244444f05562SScott Long ********************************************************************** 244544f05562SScott Long */ 244644f05562SScott Long static void arcmsr_get_hbb_config(struct AdapterControlBlock *acb) 244744f05562SScott Long { 244844f05562SScott Long char *acb_firm_model=acb->firm_model; 244944f05562SScott Long char *acb_firm_version=acb->firm_version; 245044f05562SScott Long size_t iop_firm_model=offsetof(struct HBB_RWBUFFER, 245144f05562SScott Long msgcode_rwbuffer[15]); /*firm_model,15,60-67*/ 245244f05562SScott Long size_t iop_firm_version=offsetof(struct HBB_RWBUFFER, 245344f05562SScott Long msgcode_rwbuffer[17]); /*firm_version,17,68-83*/ 245444f05562SScott Long int i; 245544f05562SScott Long 245644f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 245744f05562SScott Long 0, drv2iop_doorbell, ARCMSR_MESSAGE_GET_CONFIG); 245844f05562SScott Long if(!arcmsr_hbb_wait_msgint_ready(acb)) { 245944f05562SScott Long printf( "arcmsr%d: wait" 246044f05562SScott Long "'get adapter firmware miscellaneous data' timeout \n", acb->pci_unit); 246144f05562SScott Long } 246244f05562SScott Long i=0; 246344f05562SScott Long while(i<8) { 246444f05562SScott Long *acb_firm_model=bus_space_read_1(acb->btag[1], acb->bhandle[1], iop_firm_model+i); 246544f05562SScott Long /* 8 bytes firm_model, 15, 60-67*/ 246644f05562SScott Long acb_firm_model++; 246744f05562SScott Long i++; 246844f05562SScott Long } 246944f05562SScott Long i=0; 247044f05562SScott Long while(i<16) { 247144f05562SScott Long *acb_firm_version=bus_space_read_1(acb->btag[1], acb->bhandle[1], iop_firm_version+i); 247244f05562SScott Long /* 16 bytes firm_version, 17, 68-83*/ 247344f05562SScott Long acb_firm_version++; 247444f05562SScott Long i++; 247544f05562SScott Long } 247644f05562SScott Long printf("ARECA RAID ADAPTER%d: %s \n", acb->pci_unit, ARCMSR_DRIVER_VERSION); 247744f05562SScott Long printf("ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n", acb->pci_unit, acb->firm_version); 247844f05562SScott Long acb->firm_request_len=CHIP_REG_READ32(HBB_RWBUFFER, 247944f05562SScott Long 1, msgcode_rwbuffer[1]); /*firm_request_len, 1, 04-07*/ 248044f05562SScott Long acb->firm_numbers_queue=CHIP_REG_READ32(HBB_RWBUFFER, 248144f05562SScott Long 1, msgcode_rwbuffer[2]); /*firm_numbers_queue, 2, 08-11*/ 248244f05562SScott Long acb->firm_sdram_size=CHIP_REG_READ32(HBB_RWBUFFER, 248344f05562SScott Long 1, msgcode_rwbuffer[3]); /*firm_sdram_size, 3, 12-15*/ 248444f05562SScott Long acb->firm_ide_channels=CHIP_REG_READ32(HBB_RWBUFFER, 248544f05562SScott Long 1, msgcode_rwbuffer[4]); /*firm_ide_channels, 4, 16-19*/ 248644f05562SScott Long return; 248744f05562SScott Long } 248844f05562SScott Long /* 248944f05562SScott Long ********************************************************************** 249044f05562SScott Long ********************************************************************** 249144f05562SScott Long */ 249244f05562SScott Long static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb) 249344f05562SScott Long { 249444f05562SScott Long switch (acb->adapter_type) { 249544f05562SScott Long case ACB_ADAPTER_TYPE_A: { 249644f05562SScott Long arcmsr_get_hba_config(acb); 249744f05562SScott Long } 249844f05562SScott Long break; 249944f05562SScott Long case ACB_ADAPTER_TYPE_B: { 250044f05562SScott Long arcmsr_get_hbb_config(acb); 250144f05562SScott Long } 250244f05562SScott Long break; 250344f05562SScott Long } 250444f05562SScott Long return; 250544f05562SScott Long } 250644f05562SScott Long /* 250744f05562SScott Long ********************************************************************** 250844f05562SScott Long ********************************************************************** 250944f05562SScott Long */ 251044f05562SScott Long static void arcmsr_wait_firmware_ready( struct AdapterControlBlock *acb) 251144f05562SScott Long { 251244f05562SScott Long int timeout=0; 251344f05562SScott Long 251444f05562SScott Long switch (acb->adapter_type) { 251544f05562SScott Long case ACB_ADAPTER_TYPE_A: { 251644f05562SScott Long while ((CHIP_REG_READ32(HBA_MessageUnit, 251744f05562SScott Long 0, outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) 251844f05562SScott Long { 251944f05562SScott Long if (timeout++ > 2000) /* (2000*15)/1000 = 30 sec */ 252044f05562SScott Long { 252144f05562SScott Long printf( "arcmsr%d:" 252244f05562SScott Long "timed out waiting for firmware \n", acb->pci_unit); 252344f05562SScott Long return; 252444f05562SScott Long } 252544f05562SScott Long UDELAY(15000); /* wait 15 milli-seconds */ 252644f05562SScott Long } 252744f05562SScott Long } 252844f05562SScott Long break; 252944f05562SScott Long case ACB_ADAPTER_TYPE_B: { 253044f05562SScott Long while ((CHIP_REG_READ32(HBB_DOORBELL, 253144f05562SScott Long 0, iop2drv_doorbell) & ARCMSR_MESSAGE_FIRMWARE_OK) == 0) 253244f05562SScott Long { 253344f05562SScott Long if (timeout++ > 2000) /* (2000*15)/1000 = 30 sec */ 253444f05562SScott Long { 253544f05562SScott Long printf( "arcmsr%d:" 253644f05562SScott Long " timed out waiting for firmware \n", acb->pci_unit); 253744f05562SScott Long return; 253844f05562SScott Long } 253944f05562SScott Long UDELAY(15000); /* wait 15 milli-seconds */ 254044f05562SScott Long } 254144f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 254244f05562SScott Long 0, drv2iop_doorbell, ARCMSR_DRV2IOP_END_OF_INTERRUPT); 254344f05562SScott Long } 254444f05562SScott Long break; 254544f05562SScott Long } 254644f05562SScott Long return; 254744f05562SScott Long } 254844f05562SScott Long /* 254944f05562SScott Long ********************************************************************** 255044f05562SScott Long ********************************************************************** 255144f05562SScott Long */ 255244f05562SScott Long static void arcmsr_clear_doorbell_queue_buffer( struct AdapterControlBlock *acb) 255344f05562SScott Long { 255444f05562SScott Long switch (acb->adapter_type) { 255544f05562SScott Long case ACB_ADAPTER_TYPE_A: { 255644f05562SScott Long /* empty doorbell Qbuffer if door bell ringed */ 255744f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 255844f05562SScott Long 0, outbound_doorbell, 255944f05562SScott Long CHIP_REG_READ32(HBA_MessageUnit, 256044f05562SScott Long 0, outbound_doorbell));/*clear doorbell interrupt */ 256144f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 256244f05562SScott Long 0, inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_READ_OK); 256344f05562SScott Long } 256444f05562SScott Long break; 256544f05562SScott Long case ACB_ADAPTER_TYPE_B: { 256644f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 256744f05562SScott Long 0, iop2drv_doorbell, ARCMSR_MESSAGE_INT_CLEAR_PATTERN);/*clear interrupt and message state*/ 256844f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 256944f05562SScott Long 0, drv2iop_doorbell, ARCMSR_DRV2IOP_DATA_READ_OK); 257044f05562SScott Long /* let IOP know data has been read */ 257144f05562SScott Long } 257244f05562SScott Long break; 257344f05562SScott Long } 257444f05562SScott Long return; 257544f05562SScott Long } 257644f05562SScott Long /* 257744f05562SScott Long ************************************************************************ 257844f05562SScott Long ************************************************************************ 257944f05562SScott Long */ 258044f05562SScott Long static u_int32_t arcmsr_iop_confirm(struct AdapterControlBlock *acb) 258144f05562SScott Long { 258244f05562SScott Long unsigned long srb_phyaddr; 258344f05562SScott Long u_int32_t srb_phyaddr_hi32; 258444f05562SScott Long 258544f05562SScott Long /* 258644f05562SScott Long ******************************************************************** 258744f05562SScott Long ** here we need to tell iop 331 our freesrb.HighPart 258844f05562SScott Long ** if freesrb.HighPart is not zero 258944f05562SScott Long ******************************************************************** 259044f05562SScott Long */ 259144f05562SScott Long srb_phyaddr= (unsigned long) acb->srb_phyaddr; 259244f05562SScott Long srb_phyaddr_hi32=(u_int32_t) ((srb_phyaddr>>16)>>16); 259344f05562SScott Long switch (acb->adapter_type) { 259444f05562SScott Long case ACB_ADAPTER_TYPE_A: { 259544f05562SScott Long if(srb_phyaddr_hi32!=0) { 259644f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 259744f05562SScott Long 0, msgcode_rwbuffer[0], ARCMSR_SIGNATURE_SET_CONFIG); 259844f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 259944f05562SScott Long 0, msgcode_rwbuffer[1], srb_phyaddr_hi32); 260044f05562SScott Long CHIP_REG_WRITE32(HBA_MessageUnit, 260144f05562SScott Long 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_SET_CONFIG); 260244f05562SScott Long if(!arcmsr_hba_wait_msgint_ready(acb)) { 260344f05562SScott Long printf( "arcmsr%d:" 260444f05562SScott Long " 'set srb high part physical address' timeout \n", acb->pci_unit); 260544f05562SScott Long return FALSE; 260644f05562SScott Long } 260744f05562SScott Long } 260844f05562SScott Long } 260944f05562SScott Long break; 261044f05562SScott Long /* 261144f05562SScott Long *********************************************************************** 261244f05562SScott Long ** if adapter type B, set window of "post command Q" 261344f05562SScott Long *********************************************************************** 261444f05562SScott Long */ 261544f05562SScott Long case ACB_ADAPTER_TYPE_B: { 261644f05562SScott Long u_int32_t post_queue_phyaddr; 261744f05562SScott Long struct HBB_MessageUnit *phbbmu; 261844f05562SScott Long 261944f05562SScott Long phbbmu=(struct HBB_MessageUnit *)acb->pmu; 262044f05562SScott Long phbbmu->postq_index=0; 262144f05562SScott Long phbbmu->doneq_index=0; 262244f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 262344f05562SScott Long 0, drv2iop_doorbell, ARCMSR_MESSAGE_SET_POST_WINDOW); 262444f05562SScott Long if(!arcmsr_hbb_wait_msgint_ready(acb)) { 262544f05562SScott Long printf( "arcmsr%d:" 262644f05562SScott Long " 'set window of post command Q' timeout\n", acb->pci_unit); 262744f05562SScott Long return FALSE; 262844f05562SScott Long } 262944f05562SScott Long post_queue_phyaddr = srb_phyaddr 263044f05562SScott Long + ARCMSR_MAX_FREESRB_NUM*sizeof(struct CommandControlBlock) 263144f05562SScott Long + offsetof(struct HBB_MessageUnit, post_qbuffer); 263244f05562SScott Long CHIP_REG_WRITE32(HBB_RWBUFFER, 263344f05562SScott Long 1, msgcode_rwbuffer[0], ARCMSR_SIGNATURE_SET_CONFIG); /* driver "set config" signature */ 263444f05562SScott Long CHIP_REG_WRITE32(HBB_RWBUFFER, 263544f05562SScott Long 1, msgcode_rwbuffer[1], srb_phyaddr_hi32); /* normal should be zero */ 263644f05562SScott Long CHIP_REG_WRITE32(HBB_RWBUFFER, 263744f05562SScott Long 1, msgcode_rwbuffer[2], post_queue_phyaddr); /* postQ size (256+8)*4 */ 263844f05562SScott Long CHIP_REG_WRITE32(HBB_RWBUFFER, 263944f05562SScott Long 1, msgcode_rwbuffer[3], post_queue_phyaddr+1056); /* doneQ size (256+8)*4 */ 264044f05562SScott Long CHIP_REG_WRITE32(HBB_RWBUFFER, 264144f05562SScott Long 1, msgcode_rwbuffer[4], 1056); /* srb maxQ size must be --> [(256+8)*4] */ 264244f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 264344f05562SScott Long 0, drv2iop_doorbell, ARCMSR_MESSAGE_SET_CONFIG); 264444f05562SScott Long if(!arcmsr_hbb_wait_msgint_ready(acb)) { 264544f05562SScott Long printf( "arcmsr%d: 'set command Q window' timeout \n", acb->pci_unit); 264644f05562SScott Long return FALSE; 264744f05562SScott Long } 264844f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 264944f05562SScott Long 0, drv2iop_doorbell, ARCMSR_MESSAGE_START_DRIVER_MODE); 265044f05562SScott Long if(!arcmsr_hbb_wait_msgint_ready(acb)) { 265144f05562SScott Long printf( "arcmsr%d: 'start diver mode' timeout \n", acb->pci_unit); 265244f05562SScott Long return FALSE; 265344f05562SScott Long } 265444f05562SScott Long } 265544f05562SScott Long break; 265644f05562SScott Long } 265744f05562SScott Long return TRUE; 265844f05562SScott Long } 265944f05562SScott Long /* 266044f05562SScott Long ************************************************************************ 266144f05562SScott Long ************************************************************************ 266244f05562SScott Long */ 266344f05562SScott Long static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb) 266444f05562SScott Long { 266544f05562SScott Long switch (acb->adapter_type) 266644f05562SScott Long { 266744f05562SScott Long case ACB_ADAPTER_TYPE_A: 266844f05562SScott Long return; 266944f05562SScott Long case ACB_ADAPTER_TYPE_B: { 267044f05562SScott Long CHIP_REG_WRITE32(HBB_DOORBELL, 267144f05562SScott Long 0, drv2iop_doorbell,ARCMSR_MESSAGE_ACTIVE_EOI_MODE); 267244f05562SScott Long if(!arcmsr_hbb_wait_msgint_ready(acb)) { 267344f05562SScott Long printf( "arcmsr%d:" 267444f05562SScott Long " 'iop enable eoi mode' timeout \n", acb->pci_unit); 267544f05562SScott Long return; 267644f05562SScott Long } 267744f05562SScott Long } 267844f05562SScott Long break; 267944f05562SScott Long } 268044f05562SScott Long return; 268144f05562SScott Long } 268244f05562SScott Long /* 268344f05562SScott Long ********************************************************************** 2684ad6d6297SScott Long ********************************************************************** 2685ad6d6297SScott Long */ 2686ad6d6297SScott Long static void arcmsr_iop_init(struct AdapterControlBlock *acb) 2687ad6d6297SScott Long { 268844f05562SScott Long u_int32_t intmask_org; 2689ad6d6297SScott Long 269044f05562SScott Long /* disable all outbound interrupt */ 269144f05562SScott Long intmask_org=arcmsr_disable_allintr(acb); 269244f05562SScott Long arcmsr_wait_firmware_ready(acb); 269344f05562SScott Long arcmsr_iop_confirm(acb); 2694ad6d6297SScott Long arcmsr_get_firmware_spec(acb); 269544f05562SScott Long /*start background rebuild*/ 2696ad6d6297SScott Long arcmsr_start_adapter_bgrb(acb); 269744f05562SScott Long /* empty doorbell Qbuffer if door bell ringed */ 269844f05562SScott Long arcmsr_clear_doorbell_queue_buffer(acb); 269944f05562SScott Long arcmsr_enable_eoi_mode(acb); 270044f05562SScott Long /* enable outbound Post Queue, outbound doorbell Interrupt */ 270144f05562SScott Long arcmsr_enable_allintr(acb, intmask_org); 2702ad6d6297SScott Long acb->acb_flags |=ACB_F_IOP_INITED; 2703ad6d6297SScott Long return; 2704ad6d6297SScott Long } 2705ad6d6297SScott Long /* 2706ad6d6297SScott Long ********************************************************************** 2707f1c579b1SScott Long ********************************************************************** 2708f1c579b1SScott Long */ 2709f1c579b1SScott Long static void arcmsr_map_freesrb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2710f1c579b1SScott Long { 2711ad6d6297SScott Long struct AdapterControlBlock *acb=arg; 2712ad6d6297SScott Long struct CommandControlBlock *srb_tmp; 2713ad6d6297SScott Long u_int8_t * dma_memptr; 271444f05562SScott Long u_int32_t i; 2715ad6d6297SScott Long unsigned long srb_phyaddr=(unsigned long)segs->ds_addr; 2716f1c579b1SScott Long 2717ad6d6297SScott Long dma_memptr=acb->uncacheptr; 271844f05562SScott Long acb->srb_phyaddr=srb_phyaddr; 2719ad6d6297SScott Long srb_tmp=(struct CommandControlBlock *)dma_memptr; 2720ad6d6297SScott Long for(i=0;i<ARCMSR_MAX_FREESRB_NUM;i++) { 272144f05562SScott Long if(bus_dmamap_create(acb->dm_segs_dmat, 272244f05562SScott Long /*flags*/0, &srb_tmp->dm_segs_dmamap)!=0) { 2723ad6d6297SScott Long acb->acb_flags |= ACB_F_MAPFREESRB_FAILD; 272444f05562SScott Long printf("arcmsr%d:" 272544f05562SScott Long " srb dmamap bus_dmamap_create error\n", acb->pci_unit); 2726ad6d6297SScott Long return; 2727ad6d6297SScott Long } 2728ad6d6297SScott Long srb_tmp->cdb_shifted_phyaddr=srb_phyaddr >> 5; 2729ad6d6297SScott Long srb_tmp->acb=acb; 2730ad6d6297SScott Long acb->srbworkingQ[i]=acb->psrb_pool[i]=srb_tmp; 2731ad6d6297SScott Long srb_phyaddr=srb_phyaddr+sizeof(struct CommandControlBlock); 2732ad6d6297SScott Long srb_tmp++; 2733ad6d6297SScott Long } 2734ad6d6297SScott Long acb->vir2phy_offset=(unsigned long)srb_tmp-(unsigned long)srb_phyaddr; 2735f1c579b1SScott Long return; 2736f1c579b1SScott Long } 2737f1c579b1SScott Long /* 2738f1c579b1SScott Long ************************************************************************ 2739f1c579b1SScott Long ** 2740f1c579b1SScott Long ** 2741f1c579b1SScott Long ************************************************************************ 2742f1c579b1SScott Long */ 2743ad6d6297SScott Long static void arcmsr_free_resource(struct AdapterControlBlock *acb) 2744f1c579b1SScott Long { 2745f1c579b1SScott Long /* remove the control device */ 2746ad6d6297SScott Long if(acb->ioctl_dev != NULL) { 2747ad6d6297SScott Long destroy_dev(acb->ioctl_dev); 2748f1c579b1SScott Long } 2749ad6d6297SScott Long bus_dmamap_unload(acb->srb_dmat, acb->srb_dmamap); 2750ad6d6297SScott Long bus_dmamap_destroy(acb->srb_dmat, acb->srb_dmamap); 2751ad6d6297SScott Long bus_dma_tag_destroy(acb->srb_dmat); 2752ad6d6297SScott Long bus_dma_tag_destroy(acb->dm_segs_dmat); 2753ad6d6297SScott Long bus_dma_tag_destroy(acb->parent_dmat); 2754f1c579b1SScott Long return; 2755f1c579b1SScott Long } 2756f1c579b1SScott Long /* 2757f1c579b1SScott Long ************************************************************************ 2758f1c579b1SScott Long ************************************************************************ 2759f1c579b1SScott Long */ 2760ad6d6297SScott Long static u_int32_t arcmsr_initialize(device_t dev) 2761f1c579b1SScott Long { 2762ad6d6297SScott Long struct AdapterControlBlock *acb=device_get_softc(dev); 2763ad6d6297SScott Long u_int16_t pci_command; 276444f05562SScott Long int i, j,max_coherent_size; 2765f1c579b1SScott Long 276644f05562SScott Long switch (pci_get_devid(dev)) { 276744f05562SScott Long case PCIDevVenIDARC1201: { 276844f05562SScott Long acb->adapter_type=ACB_ADAPTER_TYPE_B; 276944f05562SScott Long max_coherent_size=ARCMSR_SRBS_POOL_SIZE 277044f05562SScott Long +(sizeof(struct HBB_MessageUnit)); 277144f05562SScott Long } 277244f05562SScott Long break; 277344f05562SScott Long case PCIDevVenIDARC1110: 277444f05562SScott Long case PCIDevVenIDARC1120: 277544f05562SScott Long case PCIDevVenIDARC1130: 277644f05562SScott Long case PCIDevVenIDARC1160: 277744f05562SScott Long case PCIDevVenIDARC1170: 277844f05562SScott Long case PCIDevVenIDARC1210: 277944f05562SScott Long case PCIDevVenIDARC1220: 278044f05562SScott Long case PCIDevVenIDARC1230: 278144f05562SScott Long case PCIDevVenIDARC1260: 278244f05562SScott Long case PCIDevVenIDARC1270: 278344f05562SScott Long case PCIDevVenIDARC1280: 278444f05562SScott Long case PCIDevVenIDARC1380: 278544f05562SScott Long case PCIDevVenIDARC1381: 278644f05562SScott Long case PCIDevVenIDARC1680: 278744f05562SScott Long case PCIDevVenIDARC1681: { 278844f05562SScott Long acb->adapter_type=ACB_ADAPTER_TYPE_A; 278944f05562SScott Long max_coherent_size=ARCMSR_SRBS_POOL_SIZE; 279044f05562SScott Long } 279144f05562SScott Long break; 279244f05562SScott Long default: { 279344f05562SScott Long printf("arcmsr%d:" 279444f05562SScott Long " unknown RAID adapter type \n", device_get_unit(dev)); 279544f05562SScott Long return ENOMEM; 279644f05562SScott Long } 279744f05562SScott Long } 2798f1c579b1SScott Long #if __FreeBSD_version >= 502010 2799f1c579b1SScott Long if(bus_dma_tag_create( /*parent*/ NULL, 2800f1c579b1SScott Long /*alignemnt*/ 1, 2801f1c579b1SScott Long /*boundary*/ 0, 2802701d9f1fSScott Long /*lowaddr*/ BUS_SPACE_MAXADDR, 2803f1c579b1SScott Long /*highaddr*/ BUS_SPACE_MAXADDR, 2804f1c579b1SScott Long /*filter*/ NULL, 2805f1c579b1SScott Long /*filterarg*/ NULL, 2806f1c579b1SScott Long /*maxsize*/ BUS_SPACE_MAXSIZE_32BIT, 2807f1c579b1SScott Long /*nsegments*/ BUS_SPACE_UNRESTRICTED, 2808f1c579b1SScott Long /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, 2809f1c579b1SScott Long /*flags*/ 0, 2810f1c579b1SScott Long /*lockfunc*/ NULL, 2811f1c579b1SScott Long /*lockarg*/ NULL, 2812ad6d6297SScott Long &acb->parent_dmat) != 0) 2813f1c579b1SScott Long #else 2814f1c579b1SScott Long if(bus_dma_tag_create( /*parent*/ NULL, 2815f1c579b1SScott Long /*alignemnt*/ 1, 2816f1c579b1SScott Long /*boundary*/ 0, 2817701d9f1fSScott Long /*lowaddr*/ BUS_SPACE_MAXADDR, 2818f1c579b1SScott Long /*highaddr*/ BUS_SPACE_MAXADDR, 2819f1c579b1SScott Long /*filter*/ NULL, 2820f1c579b1SScott Long /*filterarg*/ NULL, 2821f1c579b1SScott Long /*maxsize*/ BUS_SPACE_MAXSIZE_32BIT, 2822f1c579b1SScott Long /*nsegments*/ BUS_SPACE_UNRESTRICTED, 2823f1c579b1SScott Long /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, 2824f1c579b1SScott Long /*flags*/ 0, 2825ad6d6297SScott Long &acb->parent_dmat) != 0) 2826f1c579b1SScott Long #endif 2827f1c579b1SScott Long { 282844f05562SScott Long printf("arcmsr%d: parent_dmat bus_dma_tag_create failure!\n", device_get_unit(dev)); 2829f1c579b1SScott Long return ENOMEM; 2830f1c579b1SScott Long } 2831f1c579b1SScott Long /* Create a single tag describing a region large enough to hold all of the s/g lists we will need. */ 2832f1c579b1SScott Long #if __FreeBSD_version >= 502010 2833ad6d6297SScott Long if(bus_dma_tag_create( /*parent_dmat*/ acb->parent_dmat, 2834f1c579b1SScott Long /*alignment*/ 1, 2835f1c579b1SScott Long /*boundary*/ 0, 2836f1c579b1SScott Long /*lowaddr*/ BUS_SPACE_MAXADDR, 2837f1c579b1SScott Long /*highaddr*/ BUS_SPACE_MAXADDR, 2838f1c579b1SScott Long /*filter*/ NULL, 2839f1c579b1SScott Long /*filterarg*/ NULL, 2840f1c579b1SScott Long /*maxsize*/ MAXBSIZE, 2841f1c579b1SScott Long /*nsegments*/ ARCMSR_MAX_SG_ENTRIES, 2842f1c579b1SScott Long /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, 2843ad6d6297SScott Long /*flags*/ 0, 2844f1c579b1SScott Long /*lockfunc*/ busdma_lock_mutex, 2845579ec1a5SScott Long #if __FreeBSD_version >= 700025 28465878cbecSScott Long /*lockarg*/ &acb->qbuffer_lock, 2847579ec1a5SScott Long #else 2848579ec1a5SScott Long /*lockarg*/ &Giant, 2849579ec1a5SScott Long #endif 2850ad6d6297SScott Long &acb->dm_segs_dmat) != 0) 2851f1c579b1SScott Long #else 2852ad6d6297SScott Long if(bus_dma_tag_create( /*parent_dmat*/ acb->parent_dmat, 2853f1c579b1SScott Long /*alignment*/ 1, 2854f1c579b1SScott Long /*boundary*/ 0, 2855f1c579b1SScott Long /*lowaddr*/ BUS_SPACE_MAXADDR, 2856f1c579b1SScott Long /*highaddr*/ BUS_SPACE_MAXADDR, 2857f1c579b1SScott Long /*filter*/ NULL, 2858f1c579b1SScott Long /*filterarg*/ NULL, 2859f1c579b1SScott Long /*maxsize*/ MAXBSIZE, 2860f1c579b1SScott Long /*nsegments*/ ARCMSR_MAX_SG_ENTRIES, 2861f1c579b1SScott Long /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, 2862ad6d6297SScott Long /*flags*/ 0, 2863ad6d6297SScott Long &acb->dm_segs_dmat) != 0) 2864f1c579b1SScott Long #endif 2865f1c579b1SScott Long { 2866ad6d6297SScott Long bus_dma_tag_destroy(acb->parent_dmat); 286744f05562SScott Long printf("arcmsr%d: dm_segs_dmat bus_dma_tag_create failure!\n", device_get_unit(dev)); 2868f1c579b1SScott Long return ENOMEM; 2869f1c579b1SScott Long } 2870ad6d6297SScott Long /* DMA tag for our srb structures.... Allocate the freesrb memory */ 2871f1c579b1SScott Long #if __FreeBSD_version >= 502010 2872ad6d6297SScott Long if(bus_dma_tag_create( /*parent_dmat*/ acb->parent_dmat, 287344f05562SScott Long /*alignment*/ 0x20, 2874f1c579b1SScott Long /*boundary*/ 0, 2875f1c579b1SScott Long /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT, 2876f1c579b1SScott Long /*highaddr*/ BUS_SPACE_MAXADDR, 2877f1c579b1SScott Long /*filter*/ NULL, 2878f1c579b1SScott Long /*filterarg*/ NULL, 287944f05562SScott Long /*maxsize*/ max_coherent_size, 2880f1c579b1SScott Long /*nsegments*/ 1, 2881f1c579b1SScott Long /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, 2882701d9f1fSScott Long /*flags*/ 0, 2883f1c579b1SScott Long /*lockfunc*/ NULL, 2884f1c579b1SScott Long /*lockarg*/ NULL, 2885ad6d6297SScott Long &acb->srb_dmat) != 0) 2886f1c579b1SScott Long #else 2887ad6d6297SScott Long if(bus_dma_tag_create( /*parent_dmat*/ acb->parent_dmat, 288844f05562SScott Long /*alignment*/ 0x20, 2889f1c579b1SScott Long /*boundary*/ 0, 2890f1c579b1SScott Long /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT, 2891f1c579b1SScott Long /*highaddr*/ BUS_SPACE_MAXADDR, 2892f1c579b1SScott Long /*filter*/ NULL, 2893f1c579b1SScott Long /*filterarg*/ NULL, 289444f05562SScott Long /*maxsize*/ max_coherent_size, 2895f1c579b1SScott Long /*nsegments*/ 1, 2896f1c579b1SScott Long /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, 2897701d9f1fSScott Long /*flags*/ 0, 2898ad6d6297SScott Long &acb->srb_dmat) != 0) 2899f1c579b1SScott Long #endif 2900f1c579b1SScott Long { 2901ad6d6297SScott Long bus_dma_tag_destroy(acb->dm_segs_dmat); 2902ad6d6297SScott Long bus_dma_tag_destroy(acb->parent_dmat); 290344f05562SScott Long printf("arcmsr%d: srb_dmat bus_dma_tag_create failure!\n", device_get_unit(dev)); 2904f1c579b1SScott Long return ENXIO; 2905f1c579b1SScott Long } 2906f1c579b1SScott Long /* Allocation for our srbs */ 2907ad6d6297SScott Long if(bus_dmamem_alloc(acb->srb_dmat, (void **)&acb->uncacheptr 2908641182baSXin LI , BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, &acb->srb_dmamap) != 0) { 2909ad6d6297SScott Long bus_dma_tag_destroy(acb->srb_dmat); 2910ad6d6297SScott Long bus_dma_tag_destroy(acb->dm_segs_dmat); 2911ad6d6297SScott Long bus_dma_tag_destroy(acb->parent_dmat); 291244f05562SScott Long printf("arcmsr%d: srb_dmat bus_dmamem_alloc failure!\n", device_get_unit(dev)); 2913f1c579b1SScott Long return ENXIO; 2914f1c579b1SScott Long } 2915f1c579b1SScott Long /* And permanently map them */ 2916ad6d6297SScott Long if(bus_dmamap_load(acb->srb_dmat, acb->srb_dmamap, acb->uncacheptr 291744f05562SScott Long , max_coherent_size, arcmsr_map_freesrb, acb, /*flags*/0)) { 2918ad6d6297SScott Long bus_dma_tag_destroy(acb->srb_dmat); 2919ad6d6297SScott Long bus_dma_tag_destroy(acb->dm_segs_dmat); 2920ad6d6297SScott Long bus_dma_tag_destroy(acb->parent_dmat); 292144f05562SScott Long printf("arcmsr%d: srb_dmat bus_dmamap_load failure!\n", device_get_unit(dev)); 2922f1c579b1SScott Long return ENXIO; 2923f1c579b1SScott Long } 2924f1c579b1SScott Long pci_command=pci_read_config(dev, PCIR_COMMAND, 2); 2925f1c579b1SScott Long pci_command |= PCIM_CMD_BUSMASTEREN; 2926f1c579b1SScott Long pci_command |= PCIM_CMD_PERRESPEN; 2927f1c579b1SScott Long pci_command |= PCIM_CMD_MWRICEN; 2928f1c579b1SScott Long /* Enable Busmaster/Mem */ 2929f1c579b1SScott Long pci_command |= PCIM_CMD_MEMEN; 2930f1c579b1SScott Long pci_write_config(dev, PCIR_COMMAND, pci_command, 2); 293144f05562SScott Long switch(acb->adapter_type) { 293244f05562SScott Long case ACB_ADAPTER_TYPE_A: { 293344f05562SScott Long u_int32_t rid0=PCIR_BAR(0); 293444f05562SScott Long vm_offset_t mem_base0; 293544f05562SScott Long 293644f05562SScott Long acb->sys_res_arcmsr[0]=bus_alloc_resource(dev, 293744f05562SScott Long SYS_RES_MEMORY, &rid0, 0ul, ~0ul, 0x1000, RF_ACTIVE); 293844f05562SScott Long if(acb->sys_res_arcmsr[0] == NULL) { 2939ad6d6297SScott Long arcmsr_free_resource(acb); 294044f05562SScott Long printf("arcmsr%d:" 294144f05562SScott Long " bus_alloc_resource failure!\n", device_get_unit(dev)); 2942f1c579b1SScott Long return ENOMEM; 2943f1c579b1SScott Long } 294444f05562SScott Long if(rman_get_start(acb->sys_res_arcmsr[0]) <= 0) { 2945ad6d6297SScott Long arcmsr_free_resource(acb); 294644f05562SScott Long printf("arcmsr%d:" 294744f05562SScott Long " rman_get_start failure!\n", device_get_unit(dev)); 2948f1c579b1SScott Long return ENXIO; 2949f1c579b1SScott Long } 295044f05562SScott Long mem_base0=(vm_offset_t) rman_get_virtual(acb->sys_res_arcmsr[0]); 295144f05562SScott Long if(mem_base0==0) { 2952ad6d6297SScott Long arcmsr_free_resource(acb); 295344f05562SScott Long printf("arcmsr%d:" 295444f05562SScott Long " rman_get_virtual failure!\n", device_get_unit(dev)); 2955f1c579b1SScott Long return ENXIO; 2956f1c579b1SScott Long } 295744f05562SScott Long acb->btag[0]=rman_get_bustag(acb->sys_res_arcmsr[0]); 295844f05562SScott Long acb->bhandle[0]=rman_get_bushandle(acb->sys_res_arcmsr[0]); 295944f05562SScott Long acb->pmu=(struct MessageUnit_UNION *)mem_base0; 296044f05562SScott Long } 296144f05562SScott Long break; 296244f05562SScott Long case ACB_ADAPTER_TYPE_B: { 296344f05562SScott Long struct HBB_MessageUnit *phbbmu; 296444f05562SScott Long struct CommandControlBlock *freesrb; 296544f05562SScott Long u_int32_t rid[]={ PCIR_BAR(0), PCIR_BAR(2) }; 296644f05562SScott Long vm_offset_t mem_base[]={0,0}; 296744f05562SScott Long for(i=0; i<2; i++) { 296844f05562SScott Long if(i==0) { 296944f05562SScott Long acb->sys_res_arcmsr[i]=bus_alloc_resource(dev, 297044f05562SScott Long SYS_RES_MEMORY, &rid[i], 297144f05562SScott Long 0x20400, 0x20400+sizeof(struct HBB_DOORBELL), 297244f05562SScott Long sizeof(struct HBB_DOORBELL), RF_ACTIVE); 297344f05562SScott Long } else { 297444f05562SScott Long acb->sys_res_arcmsr[i]=bus_alloc_resource(dev, 297544f05562SScott Long SYS_RES_MEMORY, &rid[i], 297644f05562SScott Long 0x0fa00, 0x0fa00+sizeof(struct HBB_RWBUFFER), 297744f05562SScott Long sizeof(struct HBB_RWBUFFER), RF_ACTIVE); 297844f05562SScott Long } 297944f05562SScott Long if(acb->sys_res_arcmsr[i] == NULL) { 298044f05562SScott Long arcmsr_free_resource(acb); 298144f05562SScott Long printf("arcmsr%d:" 298244f05562SScott Long " bus_alloc_resource %d failure!\n", device_get_unit(dev), i); 298344f05562SScott Long return ENOMEM; 298444f05562SScott Long } 298544f05562SScott Long if(rman_get_start(acb->sys_res_arcmsr[i]) <= 0) { 298644f05562SScott Long arcmsr_free_resource(acb); 298744f05562SScott Long printf("arcmsr%d:" 298844f05562SScott Long " rman_get_start %d failure!\n", device_get_unit(dev), i); 298944f05562SScott Long return ENXIO; 299044f05562SScott Long } 299144f05562SScott Long mem_base[i]=(vm_offset_t) rman_get_virtual(acb->sys_res_arcmsr[i]); 299244f05562SScott Long if(mem_base[i]==0) { 299344f05562SScott Long arcmsr_free_resource(acb); 299444f05562SScott Long printf("arcmsr%d:" 299544f05562SScott Long " rman_get_virtual %d failure!\n", device_get_unit(dev), i); 299644f05562SScott Long return ENXIO; 299744f05562SScott Long } 299844f05562SScott Long acb->btag[i]=rman_get_bustag(acb->sys_res_arcmsr[i]); 299944f05562SScott Long acb->bhandle[i]=rman_get_bushandle(acb->sys_res_arcmsr[i]); 300044f05562SScott Long } 300144f05562SScott Long freesrb=(struct CommandControlBlock *)acb->uncacheptr; 300244f05562SScott Long acb->pmu=(struct MessageUnit_UNION *)&freesrb[ARCMSR_MAX_FREESRB_NUM]; 300344f05562SScott Long phbbmu=(struct HBB_MessageUnit *)acb->pmu; 300444f05562SScott Long phbbmu->hbb_doorbell=(struct HBB_DOORBELL *)mem_base[0]; 300544f05562SScott Long phbbmu->hbb_rwbuffer=(struct HBB_RWBUFFER *)mem_base[1]; 300644f05562SScott Long } 300744f05562SScott Long break; 300844f05562SScott Long } 3009ad6d6297SScott Long if(acb->acb_flags & ACB_F_MAPFREESRB_FAILD) { 3010ad6d6297SScott Long arcmsr_free_resource(acb); 301144f05562SScott Long printf("arcmsr%d: map free srb failure!\n", device_get_unit(dev)); 3012f1c579b1SScott Long return ENXIO; 3013f1c579b1SScott Long } 3014ad6d6297SScott Long acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED 3015ad6d6297SScott Long |ACB_F_MESSAGE_RQBUFFER_CLEARED 301644f05562SScott Long |ACB_F_MESSAGE_WQBUFFER_READ); 3017ad6d6297SScott Long acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER; 3018ad6d6297SScott Long /* 3019ad6d6297SScott Long ******************************************************************** 3020ad6d6297SScott Long ** init raid volume state 3021ad6d6297SScott Long ******************************************************************** 3022ad6d6297SScott Long */ 3023ad6d6297SScott Long for(i=0;i<ARCMSR_MAX_TARGETID;i++) { 3024ad6d6297SScott Long for(j=0;j<ARCMSR_MAX_TARGETLUN;j++) { 302544f05562SScott Long acb->devstate[i][j]=ARECA_RAID_GONE; 3026ad6d6297SScott Long } 3027ad6d6297SScott Long } 3028ad6d6297SScott Long arcmsr_iop_init(acb); 3029f1c579b1SScott Long return(0); 3030f1c579b1SScott Long } 3031f1c579b1SScott Long /* 3032f1c579b1SScott Long ************************************************************************ 3033f1c579b1SScott Long ************************************************************************ 3034f1c579b1SScott Long */ 3035f2aa0e9fSWarner Losh static int arcmsr_attach(device_t dev) 3036f1c579b1SScott Long { 3037ad6d6297SScott Long struct AdapterControlBlock *acb=(struct AdapterControlBlock *)device_get_softc(dev); 3038ad6d6297SScott Long u_int32_t unit=device_get_unit(dev); 3039f1c579b1SScott Long struct ccb_setasync csa; 3040f1c579b1SScott Long struct cam_devq *devq; /* Device Queue to use for this SIM */ 3041f1c579b1SScott Long struct resource *irqres; 3042f1c579b1SScott Long int rid; 3043f1c579b1SScott Long 3044ad6d6297SScott Long if(acb == NULL) { 3045ad6d6297SScott Long printf("arcmsr%d: cannot allocate softc\n", unit); 3046ad6d6297SScott Long return (ENOMEM); 3047ad6d6297SScott Long } 30485878cbecSScott Long ARCMSR_LOCK_INIT(&acb->qbuffer_lock, "arcmsr Q buffer lock"); 3049ad6d6297SScott Long if(arcmsr_initialize(dev)) { 3050ad6d6297SScott Long printf("arcmsr%d: initialize failure!\n", unit); 30515878cbecSScott Long ARCMSR_LOCK_DESTROY(&acb->qbuffer_lock); 3052f1c579b1SScott Long return ENXIO; 3053f1c579b1SScott Long } 3054f1c579b1SScott Long /* After setting up the adapter, map our interrupt */ 3055f1c579b1SScott Long rid=0; 3056ad6d6297SScott Long irqres=bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0ul, ~0ul, 1, RF_SHAREABLE | RF_ACTIVE); 3057ad6d6297SScott Long if(irqres == NULL || 305844f05562SScott Long #if __FreeBSD_version >= 700025 3059ad6d6297SScott Long bus_setup_intr(dev, irqres, INTR_TYPE_CAM|INTR_ENTROPY|INTR_MPSAFE 30605878cbecSScott Long , NULL, arcmsr_intr_handler, acb, &acb->ih)) { 306144f05562SScott Long #else 306244f05562SScott Long bus_setup_intr(dev, irqres, INTR_TYPE_CAM|INTR_ENTROPY|INTR_MPSAFE 306344f05562SScott Long , arcmsr_intr_handler, acb, &acb->ih)) { 306444f05562SScott Long #endif 3065ad6d6297SScott Long arcmsr_free_resource(acb); 30665878cbecSScott Long ARCMSR_LOCK_DESTROY(&acb->qbuffer_lock); 3067f1c579b1SScott Long printf("arcmsr%d: unable to register interrupt handler!\n", unit); 3068f1c579b1SScott Long return ENXIO; 3069f1c579b1SScott Long } 3070ad6d6297SScott Long acb->irqres=irqres; 3071ad6d6297SScott Long acb->pci_dev=dev; 3072ad6d6297SScott Long acb->pci_unit=unit; 3073f1c579b1SScott Long /* 3074f1c579b1SScott Long * Now let the CAM generic SCSI layer find the SCSI devices on 3075f1c579b1SScott Long * the bus * start queue to reset to the idle loop. * 3076f1c579b1SScott Long * Create device queue of SIM(s) * (MAX_START_JOB - 1) : 3077f1c579b1SScott Long * max_sim_transactions 3078f1c579b1SScott Long */ 3079f1c579b1SScott Long devq=cam_simq_alloc(ARCMSR_MAX_START_JOB); 3080ad6d6297SScott Long if(devq == NULL) { 3081ad6d6297SScott Long arcmsr_free_resource(acb); 3082ad6d6297SScott Long bus_release_resource(dev, SYS_RES_IRQ, 0, acb->irqres); 30835878cbecSScott Long ARCMSR_LOCK_DESTROY(&acb->qbuffer_lock); 3084ad6d6297SScott Long printf("arcmsr%d: cam_simq_alloc failure!\n", unit); 3085f1c579b1SScott Long return ENXIO; 3086f1c579b1SScott Long } 308744f05562SScott Long #if __FreeBSD_version >= 700025 30882b83592fSScott Long acb->psim=cam_sim_alloc(arcmsr_action, arcmsr_poll, 30895878cbecSScott Long "arcmsr", acb, unit, &acb->qbuffer_lock, 1, 30902b83592fSScott Long ARCMSR_MAX_OUTSTANDING_CMD, devq); 309144f05562SScott Long #else 309244f05562SScott Long acb->psim=cam_sim_alloc(arcmsr_action, arcmsr_poll, 309344f05562SScott Long "arcmsr", acb, unit, 1, 309444f05562SScott Long ARCMSR_MAX_OUTSTANDING_CMD, devq); 309544f05562SScott Long #endif 3096ad6d6297SScott Long if(acb->psim == NULL) { 3097ad6d6297SScott Long arcmsr_free_resource(acb); 3098ad6d6297SScott Long bus_release_resource(dev, SYS_RES_IRQ, 0, acb->irqres); 3099f1c579b1SScott Long cam_simq_free(devq); 31005878cbecSScott Long ARCMSR_LOCK_DESTROY(&acb->qbuffer_lock); 3101ad6d6297SScott Long printf("arcmsr%d: cam_sim_alloc failure!\n", unit); 3102f1c579b1SScott Long return ENXIO; 3103f1c579b1SScott Long } 31045878cbecSScott Long ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); 3105f40b4cabSScott Long #if __FreeBSD_version >= 700044 3106b50569b7SScott Long if(xpt_bus_register(acb->psim, dev, 0) != CAM_SUCCESS) { 310744f05562SScott Long #else 310844f05562SScott Long if(xpt_bus_register(acb->psim, 0) != CAM_SUCCESS) { 310944f05562SScott Long #endif 3110ad6d6297SScott Long arcmsr_free_resource(acb); 3111ad6d6297SScott Long bus_release_resource(dev, SYS_RES_IRQ, 0, acb->irqres); 3112ad6d6297SScott Long cam_sim_free(acb->psim, /*free_devq*/TRUE); 31135878cbecSScott Long ARCMSR_LOCK_DESTROY(&acb->qbuffer_lock); 3114ad6d6297SScott Long printf("arcmsr%d: xpt_bus_register failure!\n", unit); 3115f1c579b1SScott Long return ENXIO; 3116f1c579b1SScott Long } 3117ad6d6297SScott Long if(xpt_create_path(&acb->ppath, /* periph */ NULL 3118ad6d6297SScott Long , cam_sim_path(acb->psim) 3119ad6d6297SScott Long , CAM_TARGET_WILDCARD 3120ad6d6297SScott Long , CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 3121ad6d6297SScott Long arcmsr_free_resource(acb); 3122ad6d6297SScott Long bus_release_resource(dev, SYS_RES_IRQ, 0, acb->irqres); 3123ad6d6297SScott Long xpt_bus_deregister(cam_sim_path(acb->psim)); 3124ad6d6297SScott Long cam_sim_free(acb->psim, /* free_simq */ TRUE); 31255878cbecSScott Long ARCMSR_LOCK_DESTROY(&acb->qbuffer_lock); 3126ad6d6297SScott Long printf("arcmsr%d: xpt_create_path failure!\n", unit); 3127f1c579b1SScott Long return ENXIO; 3128f1c579b1SScott Long } 3129f1c579b1SScott Long /* 3130f1c579b1SScott Long **************************************************** 3131f1c579b1SScott Long */ 3132ad6d6297SScott Long xpt_setup_ccb(&csa.ccb_h, acb->ppath, /*priority*/5); 3133f1c579b1SScott Long csa.ccb_h.func_code=XPT_SASYNC_CB; 3134f1c579b1SScott Long csa.event_enable=AC_FOUND_DEVICE|AC_LOST_DEVICE; 3135f1c579b1SScott Long csa.callback=arcmsr_async; 3136ad6d6297SScott Long csa.callback_arg=acb->psim; 3137f1c579b1SScott Long xpt_action((union ccb *)&csa); 31385878cbecSScott Long ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); 3139f1c579b1SScott Long /* Create the control device. */ 3140ad6d6297SScott Long acb->ioctl_dev=make_dev(&arcmsr_cdevsw 3141ad6d6297SScott Long , unit 3142ad6d6297SScott Long , UID_ROOT 3143ad6d6297SScott Long , GID_WHEEL /* GID_OPERATOR */ 3144ad6d6297SScott Long , S_IRUSR | S_IWUSR 3145ad6d6297SScott Long , "arcmsr%d", unit); 3146f1c579b1SScott Long #if __FreeBSD_version < 503000 3147ad6d6297SScott Long acb->ioctl_dev->si_drv1=acb; 3148f1c579b1SScott Long #endif 3149f1c579b1SScott Long #if __FreeBSD_version > 500005 3150ad6d6297SScott Long (void)make_dev_alias(acb->ioctl_dev, "arc%d", unit); 3151f1c579b1SScott Long #endif 3152f1c579b1SScott Long return 0; 3153f1c579b1SScott Long } 3154f1c579b1SScott Long /* 3155f1c579b1SScott Long ************************************************************************ 3156f1c579b1SScott Long ************************************************************************ 3157f1c579b1SScott Long */ 3158f2aa0e9fSWarner Losh static int arcmsr_probe(device_t dev) 3159f1c579b1SScott Long { 3160ad6d6297SScott Long u_int32_t id; 3161ad6d6297SScott Long static char buf[256]; 3162ad6d6297SScott Long char *type; 3163ad6d6297SScott Long int raid6 = 1; 3164ad6d6297SScott Long 3165ad6d6297SScott Long if (pci_get_vendor(dev) != PCI_VENDOR_ID_ARECA) { 3166ad6d6297SScott Long return (ENXIO); 3167ad6d6297SScott Long } 3168ad6d6297SScott Long switch(id=pci_get_devid(dev)) { 3169f1c579b1SScott Long case PCIDevVenIDARC1110: 3170f1c579b1SScott Long case PCIDevVenIDARC1210: 317144f05562SScott Long case PCIDevVenIDARC1201: 3172ad6d6297SScott Long raid6 = 0; 3173ad6d6297SScott Long /*FALLTHRU*/ 3174ad6d6297SScott Long case PCIDevVenIDARC1120: 3175ad6d6297SScott Long case PCIDevVenIDARC1130: 3176ad6d6297SScott Long case PCIDevVenIDARC1160: 3177ad6d6297SScott Long case PCIDevVenIDARC1170: 3178f1c579b1SScott Long case PCIDevVenIDARC1220: 3179f1c579b1SScott Long case PCIDevVenIDARC1230: 3180f1c579b1SScott Long case PCIDevVenIDARC1260: 3181ad6d6297SScott Long case PCIDevVenIDARC1270: 3182ad6d6297SScott Long case PCIDevVenIDARC1280: 3183ad6d6297SScott Long type = "SATA"; 3184ad6d6297SScott Long break; 3185ad6d6297SScott Long case PCIDevVenIDARC1380: 3186ad6d6297SScott Long case PCIDevVenIDARC1381: 3187ad6d6297SScott Long case PCIDevVenIDARC1680: 3188ad6d6297SScott Long case PCIDevVenIDARC1681: 3189ad6d6297SScott Long type = "SAS"; 3190ad6d6297SScott Long break; 3191ad6d6297SScott Long default: 3192ad6d6297SScott Long type = "X-TYPE"; 3193ad6d6297SScott Long break; 3194f1c579b1SScott Long } 3195ad6d6297SScott Long sprintf(buf, "Areca %s Host Adapter RAID Controller %s\n", type, raid6 ? "(RAID6 capable)" : ""); 3196ad6d6297SScott Long device_set_desc_copy(dev, buf); 3197ad6d6297SScott Long return 0; 3198f1c579b1SScott Long } 3199f1c579b1SScott Long /* 3200f1c579b1SScott Long ************************************************************************ 3201f1c579b1SScott Long ************************************************************************ 3202f1c579b1SScott Long */ 3203f2aa0e9fSWarner Losh static int arcmsr_shutdown(device_t dev) 3204f1c579b1SScott Long { 320544f05562SScott Long u_int32_t i; 3206ad6d6297SScott Long u_int32_t intmask_org; 3207ad6d6297SScott Long struct CommandControlBlock *srb; 3208ad6d6297SScott Long struct AdapterControlBlock *acb=(struct AdapterControlBlock *)device_get_softc(dev); 3209f1c579b1SScott Long 3210f1c579b1SScott Long /* stop adapter background rebuild */ 32115878cbecSScott Long ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); 321244f05562SScott Long /* disable all outbound interrupt */ 321344f05562SScott Long intmask_org=arcmsr_disable_allintr(acb); 3214ad6d6297SScott Long arcmsr_stop_adapter_bgrb(acb); 3215ad6d6297SScott Long arcmsr_flush_adapter_cache(acb); 3216f1c579b1SScott Long /* abort all outstanding command */ 3217ad6d6297SScott Long acb->acb_flags |= ACB_F_SCSISTOPADAPTER; 3218ad6d6297SScott Long acb->acb_flags &= ~ACB_F_IOP_INITED; 3219ad6d6297SScott Long if(acb->srboutstandingcount!=0) { 322044f05562SScott Long /*clear and abort all outbound posted Q*/ 322144f05562SScott Long arcmsr_done4abort_postqueue(acb); 322244f05562SScott Long /* talk to iop 331 outstanding command aborted*/ 3223ad6d6297SScott Long arcmsr_abort_allcmd(acb); 3224ad6d6297SScott Long for(i=0;i<ARCMSR_MAX_FREESRB_NUM;i++) { 3225ad6d6297SScott Long srb=acb->psrb_pool[i]; 3226ad6d6297SScott Long if(srb->startdone==ARCMSR_SRB_START) { 3227ad6d6297SScott Long srb->startdone=ARCMSR_SRB_ABORTED; 3228ad6d6297SScott Long srb->pccb->ccb_h.status |= CAM_REQ_ABORTED; 3229ad6d6297SScott Long arcmsr_srb_complete(srb, 1); 3230f1c579b1SScott Long } 3231f1c579b1SScott Long } 3232f1c579b1SScott Long } 3233ad6d6297SScott Long atomic_set_int(&acb->srboutstandingcount, 0); 3234ad6d6297SScott Long acb->workingsrb_doneindex=0; 3235ad6d6297SScott Long acb->workingsrb_startindex=0; 32365878cbecSScott Long ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); 3237f2aa0e9fSWarner Losh return (0); 3238f1c579b1SScott Long } 3239f1c579b1SScott Long /* 3240f1c579b1SScott Long ************************************************************************ 3241f1c579b1SScott Long ************************************************************************ 3242f1c579b1SScott Long */ 3243f2aa0e9fSWarner Losh static int arcmsr_detach(device_t dev) 3244f1c579b1SScott Long { 3245ad6d6297SScott Long struct AdapterControlBlock *acb=(struct AdapterControlBlock *)device_get_softc(dev); 324644f05562SScott Long int i; 3247f1c579b1SScott Long 32485878cbecSScott Long bus_teardown_intr(dev, acb->irqres, acb->ih); 3249f1c579b1SScott Long arcmsr_shutdown(dev); 3250ad6d6297SScott Long arcmsr_free_resource(acb); 325144f05562SScott Long for(i=0; (acb->sys_res_arcmsr[i]!=NULL) && (i<2); i++) { 325244f05562SScott Long bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(i), acb->sys_res_arcmsr[i]); 325344f05562SScott Long } 3254ad6d6297SScott Long bus_release_resource(dev, SYS_RES_IRQ, 0, acb->irqres); 32555878cbecSScott Long ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); 3256ad6d6297SScott Long xpt_async(AC_LOST_DEVICE, acb->ppath, NULL); 3257ad6d6297SScott Long xpt_free_path(acb->ppath); 3258ad6d6297SScott Long xpt_bus_deregister(cam_sim_path(acb->psim)); 3259ad6d6297SScott Long cam_sim_free(acb->psim, TRUE); 32605878cbecSScott Long ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); 32615878cbecSScott Long ARCMSR_LOCK_DESTROY(&acb->qbuffer_lock); 3262f1c579b1SScott Long return (0); 3263f1c579b1SScott Long } 3264f1c579b1SScott Long 3265f1c579b1SScott Long 3266