| Commit | Line | Data |
|---|---|---|
| 1901a965 SW |
1 | /* |
| 2 | ***************************************************************************************** | |
| 3 | ** O.S : FreeBSD | |
| 4 | ** FILE NAME : arcmsr.c | |
| 5 | ** BY : Erich Chen, Ching Huang | |
| 6 | ** Description: SCSI RAID Device Driver for | |
| 7 | ** ARECA (ARC11XX/ARC12XX/ARC13XX/ARC16XX/ARC188x) SATA/SAS RAID HOST Adapter | |
| 8 | ** ARCMSR RAID Host adapter | |
| 9 | ** [RAID controller:INTEL 331(PCI-X) 341(PCI-EXPRESS) chip set] | |
| 10 | ****************************************************************************************** | |
| 11 | ************************************************************************ | |
| 12 | ** | |
| 13 | ** Copyright (c) 2004-2010 ARECA Co. Ltd. | |
| 14 | ** Erich Chen, Taipei Taiwan All rights reserved. | |
| 15 | ** | |
| 16 | ** Redistribution and use in source and binary forms, with or without | |
| 17 | ** modification, are permitted provided that the following conditions | |
| 18 | ** are met: | |
| 19 | ** 1. Redistributions of source code must retain the above copyright | |
| 20 | ** notice, this list of conditions and the following disclaimer. | |
| 21 | ** 2. Redistributions in binary form must reproduce the above copyright | |
| 22 | ** notice, this list of conditions and the following disclaimer in the | |
| 23 | ** documentation and/or other materials provided with the distribution. | |
| 24 | ** 3. The name of the author may not be used to endorse or promote products | |
| 25 | ** derived from this software without specific prior written permission. | |
| 26 | ** | |
| 27 | ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
| 28 | ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
| 29 | ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
| 30 | ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 31 | ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT | |
| 32 | ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 33 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY | |
| 34 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 35 | **(INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF | |
| 36 | ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 37 | ************************************************************************** | |
| 38 | ** History | |
| 39 | ** | |
| 40 | ** REV# DATE NAME DESCRIPTION | |
| cc3b439c SW |
41 | ** 1.00.00.00 03/31/2004 Erich Chen First release |
| 42 | ** 1.20.00.02 11/29/2004 Erich Chen bug fix with arcmsr_bus_reset when PHY error | |
| 43 | ** 1.20.00.03 04/19/2005 Erich Chen add SATA 24 Ports adapter type support | |
| 1901a965 | 44 | ** clean unused function |
| cc3b439c | 45 | ** 1.20.00.12 09/12/2005 Erich Chen bug fix with abort command handling, |
| 1901a965 SW |
46 | ** firmware version check |
| 47 | ** and firmware update notify for hardware bug fix | |
| 48 | ** handling if none zero high part physical address | |
| 49 | ** of srb resource | |
| cc3b439c | 50 | ** 1.20.00.13 08/18/2006 Erich Chen remove pending srb and report busy |
| 1901a965 SW |
51 | ** add iop message xfer |
| 52 | ** with scsi pass-through command | |
| 53 | ** add new device id of sas raid adapters | |
| 54 | ** code fit for SPARC64 & PPC | |
| cc3b439c | 55 | ** 1.20.00.14 02/05/2007 Erich Chen bug fix for incorrect ccb_h.status report |
| 1901a965 | 56 | ** and cause g_vfs_done() read write error |
| cc3b439c SW |
57 | ** 1.20.00.15 10/10/2007 Erich Chen support new RAID adapter type ARC120x |
| 58 | ** 1.20.00.16 10/10/2009 Erich Chen Bug fix for RAID adapter type ARC120x | |
| 1901a965 SW |
59 | ** bus_dmamem_alloc() with BUS_DMA_ZERO |
| 60 | ** 1.20.00.17 07/15/2010 Ching Huang Added support ARC1880 | |
| 61 | ** report CAM_DEV_NOT_THERE instead of CAM_SEL_TIMEOUT when device failed, | |
| 62 | ** prevent cam_periph_error removing all LUN devices of one Target id | |
| 63 | ** for any one LUN device failed | |
| cc3b439c SW |
64 | ** 1.20.00.18 10/14/2010 Ching Huang Fixed "inquiry data fails comparion at DV1 step" |
| 65 | ** 10/25/2010 Ching Huang Fixed bad range input in bus_alloc_resource for ADAPTER_TYPE_B | |
| 66 | ** 1.20.00.19 11/11/2010 Ching Huang Fixed arcmsr driver prevent arcsas support for Areca SAS HBA ARC13x0 | |
| 67 | ** 1.20.00.20 12/08/2010 Ching Huang Avoid calling atomic_set_int function | |
| 68 | ** 1.20.00.21 02/08/2011 Ching Huang Implement I/O request timeout | |
| 69 | ** 02/14/2011 Ching Huang Modified pktRequestCount | |
| 70 | ** 1.20.00.21 03/03/2011 Ching Huang if a command timeout, then wait its ccb back before free it | |
| 71 | ** 1.20.00.22 07/04/2011 Ching Huang Fixed multiple MTX panic | |
| 1901a965 | 72 | ****************************************************************************************** |
| cc3b439c | 73 | * $FreeBSD: src/sys/dev/arcmsr/arcmsr.c,v 1.38 2011/08/16 08:41:37 delphij Exp $ |
| 1901a965 | 74 | */ |
| cc3b439c SW |
75 | #if 0 |
| 76 | #define ARCMSR_DEBUG1 1 | |
| 77 | #endif | |
| 1901a965 SW |
78 | #include <sys/param.h> |
| 79 | #include <sys/systm.h> | |
| 80 | #include <sys/malloc.h> | |
| 81 | #include <sys/kernel.h> | |
| 82 | #include <sys/bus.h> | |
| 83 | #include <sys/queue.h> | |
| 84 | #include <sys/stat.h> | |
| 85 | #include <sys/devicestat.h> | |
| 86 | #include <sys/kthread.h> | |
| 87 | #include <sys/module.h> | |
| 88 | #include <sys/proc.h> | |
| 89 | #include <sys/lock.h> | |
| 90 | #include <sys/sysctl.h> | |
| 91 | #include <sys/thread2.h> | |
| 92 | #include <sys/poll.h> | |
| 1901a965 SW |
93 | #include <sys/device.h> |
| 94 | #include <vm/vm.h> | |
| 95 | #include <vm/vm_param.h> | |
| 96 | #include <vm/pmap.h> | |
| 97 | ||
| 98 | #include <machine/atomic.h> | |
| 99 | #include <sys/conf.h> | |
| 100 | #include <sys/rman.h> | |
| 101 | ||
| 102 | #include <bus/cam/cam.h> | |
| 103 | #include <bus/cam/cam_ccb.h> | |
| 104 | #include <bus/cam/cam_sim.h> | |
| 105 | #include <bus/cam/cam_periph.h> | |
| 106 | #include <bus/cam/cam_xpt_periph.h> | |
| 107 | #include <bus/cam/cam_xpt_sim.h> | |
| 108 | #include <bus/cam/cam_debug.h> | |
| 109 | #include <bus/cam/scsi/scsi_all.h> | |
| 110 | #include <bus/cam/scsi/scsi_message.h> | |
| 111 | /* | |
| 112 | ************************************************************************** | |
| 113 | ************************************************************************** | |
| 114 | */ | |
| 115 | #include <sys/endian.h> | |
| 116 | #include <bus/pci/pcivar.h> | |
| 117 | #include <bus/pci/pcireg.h> | |
| 118 | #define ARCMSR_LOCK_INIT(l, s) lockinit(l, s, 0, LK_CANRECURSE) | |
| 119 | #define ARCMSR_LOCK_DESTROY(l) lockuninit(l) | |
| 120 | #define ARCMSR_LOCK_ACQUIRE(l) lockmgr(l, LK_EXCLUSIVE) | |
| 121 | #define ARCMSR_LOCK_RELEASE(l) lockmgr(l, LK_RELEASE) | |
| 122 | #define ARCMSR_LOCK_TRY(l) lockmgr(&l, LK_EXCLUSIVE|LK_NOWAIT); | |
| 123 | #define arcmsr_htole32(x) htole32(x) | |
| 124 | typedef struct lock arcmsr_lock_t; | |
| 125 | ||
| 126 | #if !defined(CAM_NEW_TRAN_CODE) | |
| 127 | #define CAM_NEW_TRAN_CODE 1 | |
| 128 | #endif | |
| 129 | ||
| cc3b439c SW |
130 | #define arcmsr_callout_init(a) callout_init_mp(a); |
| 131 | ||
| 132 | #define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.22 2011-07-04" | |
| 1901a965 | 133 | #include <dev/raid/arcmsr/arcmsr.h> |
| cc3b439c SW |
134 | #define SRB_SIZE ((sizeof(struct CommandControlBlock)+0x1f) & 0xffe0) |
| 135 | #define ARCMSR_SRBS_POOL_SIZE (SRB_SIZE * ARCMSR_MAX_FREESRB_NUM) | |
| 1901a965 SW |
136 | /* |
| 137 | ************************************************************************** | |
| 138 | ************************************************************************** | |
| 139 | */ | |
| 140 | #define CHIP_REG_READ32(s, b, r) bus_space_read_4(acb->btag[b], acb->bhandle[b], offsetof(struct s, r)) | |
| 141 | #define CHIP_REG_WRITE32(s, b, r, d) bus_space_write_4(acb->btag[b], acb->bhandle[b], offsetof(struct s, r), d) | |
| 142 | /* | |
| 143 | ************************************************************************** | |
| 144 | ************************************************************************** | |
| 145 | */ | |
| cc3b439c | 146 | static void arcmsr_free_srb(struct CommandControlBlock *srb); |
| 1901a965 SW |
147 | static struct CommandControlBlock * arcmsr_get_freesrb(struct AdapterControlBlock *acb); |
| 148 | static u_int8_t arcmsr_seek_cmd2abort(union ccb * abortccb); | |
| 149 | static int arcmsr_probe(device_t dev); | |
| 150 | static int arcmsr_attach(device_t dev); | |
| 151 | static int arcmsr_detach(device_t dev); | |
| 152 | static u_int32_t arcmsr_iop_ioctlcmd(struct AdapterControlBlock *acb, u_int32_t ioctl_cmd, caddr_t arg); | |
| 153 | static void arcmsr_iop_parking(struct AdapterControlBlock *acb); | |
| 154 | static int arcmsr_shutdown(device_t dev); | |
| 155 | static void arcmsr_interrupt(struct AdapterControlBlock *acb); | |
| 156 | static void arcmsr_polling_srbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_srb); | |
| 157 | static void arcmsr_free_resource(struct AdapterControlBlock *acb); | |
| 158 | static void arcmsr_bus_reset(struct AdapterControlBlock *acb); | |
| 159 | static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb); | |
| 160 | static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb); | |
| 161 | static void arcmsr_iop_init(struct AdapterControlBlock *acb); | |
| 162 | static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb); | |
| 163 | static void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb); | |
| 164 | static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb); | |
| 165 | static void arcmsr_srb_complete(struct CommandControlBlock *srb, int stand_flag); | |
| 166 | static void arcmsr_iop_reset(struct AdapterControlBlock *acb); | |
| 167 | static void arcmsr_report_sense_info(struct CommandControlBlock *srb); | |
| 168 | static void arcmsr_build_srb(struct CommandControlBlock *srb, bus_dma_segment_t * dm_segs, u_int32_t nseg); | |
| 169 | static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, union ccb * pccb); | |
| 170 | static int arcmsr_resume(device_t dev); | |
| 171 | static int arcmsr_suspend(device_t dev); | |
| 172 | static void arcmsr_rescanLun_cb(struct cam_periph *periph, union ccb *ccb); | |
| 173 | static void arcmsr_polling_devmap(void* arg); | |
| cc3b439c SW |
174 | static void arcmsr_srb_timeout(void* arg); |
| 175 | #ifdef ARCMSR_DEBUG1 | |
| 176 | static void arcmsr_dump_data(struct AdapterControlBlock *acb); | |
| 177 | #endif | |
| 1901a965 SW |
178 | /* |
| 179 | ************************************************************************** | |
| 180 | ************************************************************************** | |
| 181 | */ | |
| 182 | static void UDELAY(u_int32_t us) { DELAY(us); } | |
| 183 | /* | |
| 184 | ************************************************************************** | |
| 185 | ************************************************************************** | |
| 186 | */ | |
| 95696aa4 SW |
187 | static bus_dmamap_callback_t arcmsr_map_free_srb; |
| 188 | static bus_dmamap_callback_t arcmsr_execute_srb; | |
| 1901a965 SW |
189 | /* |
| 190 | ************************************************************************** | |
| 191 | ************************************************************************** | |
| 192 | */ | |
| 193 | static d_open_t arcmsr_open; | |
| 194 | static d_close_t arcmsr_close; | |
| 195 | static d_ioctl_t arcmsr_ioctl; | |
| 196 | ||
| 197 | static device_method_t arcmsr_methods[]={ | |
| 198 | DEVMETHOD(device_probe, arcmsr_probe), | |
| 199 | DEVMETHOD(device_attach, arcmsr_attach), | |
| 200 | DEVMETHOD(device_detach, arcmsr_detach), | |
| 201 | DEVMETHOD(device_shutdown, arcmsr_shutdown), | |
| 202 | DEVMETHOD(device_suspend, arcmsr_suspend), | |
| 203 | DEVMETHOD(device_resume, arcmsr_resume), | |
| 204 | DEVMETHOD(bus_print_child, bus_generic_print_child), | |
| 205 | DEVMETHOD(bus_driver_added, bus_generic_driver_added), | |
| 206 | { 0, 0 } | |
| 207 | }; | |
| 208 | ||
| 209 | static driver_t arcmsr_driver={ | |
| 210 | "arcmsr", arcmsr_methods, sizeof(struct AdapterControlBlock) | |
| 211 | }; | |
| 212 | ||
| 213 | static devclass_t arcmsr_devclass; | |
| aa2b9d05 | 214 | DRIVER_MODULE(arcmsr, pci, arcmsr_driver, arcmsr_devclass, NULL, NULL); |
| 365ad4c8 | 215 | MODULE_VERSION(arcmsr, 1); |
| 1901a965 SW |
216 | MODULE_DEPEND(arcmsr, pci, 1, 1, 1); |
| 217 | MODULE_DEPEND(arcmsr, cam, 1, 1, 1); | |
| 218 | #ifndef BUS_DMA_COHERENT | |
| 219 | #define BUS_DMA_COHERENT 0x04 /* hint: map memory in a coherent way */ | |
| 220 | #endif | |
| 221 | ||
| 222 | static struct dev_ops arcmsr_ops = { | |
| 223 | { "arcmsr", 0, 0 }, | |
| 224 | .d_open = arcmsr_open, /* open */ | |
| 225 | .d_close = arcmsr_close, /* close */ | |
| 226 | .d_ioctl = arcmsr_ioctl, /* ioctl */ | |
| 227 | }; | |
| 228 | ||
| fb8c9539 SW |
229 | static int arcmsr_msi_enable = 1; |
| 230 | TUNABLE_INT("hw.arcmsr.msi.enable", &arcmsr_msi_enable); | |
| 231 | ||
| 232 | ||
| 1901a965 SW |
233 | /* |
| 234 | ************************************************************************** | |
| 235 | ************************************************************************** | |
| 236 | */ | |
| 237 | ||
| 238 | static int | |
| 239 | arcmsr_open(struct dev_open_args *ap) | |
| 240 | { | |
| 241 | cdev_t dev = ap->a_head.a_dev; | |
| 242 | struct AdapterControlBlock *acb=dev->si_drv1; | |
| 243 | ||
| 244 | if(acb==NULL) { | |
| 245 | return ENXIO; | |
| 246 | } | |
| 247 | return 0; | |
| 248 | } | |
| 249 | ||
| 250 | /* | |
| 251 | ************************************************************************** | |
| 252 | ************************************************************************** | |
| 253 | */ | |
| 254 | ||
| 255 | static int | |
| 256 | arcmsr_close(struct dev_close_args *ap) | |
| 257 | { | |
| 258 | cdev_t dev = ap->a_head.a_dev; | |
| 259 | struct AdapterControlBlock *acb=dev->si_drv1; | |
| 260 | ||
| 261 | if(acb==NULL) { | |
| 262 | return ENXIO; | |
| 263 | } | |
| 264 | return 0; | |
| 265 | } | |
| 266 | ||
| 267 | /* | |
| 268 | ************************************************************************** | |
| 269 | ************************************************************************** | |
| 270 | */ | |
| 271 | ||
| 272 | static int | |
| 273 | arcmsr_ioctl(struct dev_ioctl_args *ap) | |
| 274 | { | |
| 275 | cdev_t dev = ap->a_head.a_dev; | |
| 276 | u_long ioctl_cmd = ap->a_cmd; | |
| 277 | caddr_t arg = ap->a_data; | |
| 278 | struct AdapterControlBlock *acb=dev->si_drv1; | |
| 279 | ||
| 280 | if(acb==NULL) { | |
| 281 | return ENXIO; | |
| 282 | } | |
| 283 | return(arcmsr_iop_ioctlcmd(acb, ioctl_cmd, arg)); | |
| 284 | } | |
| 285 | ||
| 286 | /* | |
| 287 | ********************************************************************** | |
| 288 | ********************************************************************** | |
| 289 | */ | |
| 290 | static u_int32_t arcmsr_disable_allintr( struct AdapterControlBlock *acb) | |
| 291 | { | |
| 292 | u_int32_t intmask_org=0; | |
| 293 | ||
| 294 | switch (acb->adapter_type) { | |
| 295 | case ACB_ADAPTER_TYPE_A: { | |
| 296 | /* disable all outbound interrupt */ | |
| 297 | intmask_org=CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_intmask); /* disable outbound message0 int */ | |
| 298 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intmask, intmask_org|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE); | |
| 299 | } | |
| 300 | break; | |
| 301 | case ACB_ADAPTER_TYPE_B: { | |
| 302 | /* disable all outbound interrupt */ | |
| 303 | intmask_org=CHIP_REG_READ32(HBB_DOORBELL, | |
| 304 | 0, iop2drv_doorbell_mask) & (~ARCMSR_IOP2DRV_MESSAGE_CMD_DONE); /* disable outbound message0 int */ | |
| 305 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, iop2drv_doorbell_mask, 0); /* disable all interrupt */ | |
| 306 | } | |
| 307 | break; | |
| 308 | case ACB_ADAPTER_TYPE_C: { | |
| 309 | /* disable all outbound interrupt */ | |
| 310 | intmask_org=CHIP_REG_READ32(HBC_MessageUnit, 0, host_int_mask) ; /* disable outbound message0 int */ | |
| 311 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, host_int_mask, intmask_org|ARCMSR_HBCMU_ALL_INTMASKENABLE); | |
| 312 | } | |
| 313 | break; | |
| 314 | } | |
| 315 | return(intmask_org); | |
| 316 | } | |
| 317 | /* | |
| 318 | ********************************************************************** | |
| 319 | ********************************************************************** | |
| 320 | */ | |
| 321 | static void arcmsr_enable_allintr( struct AdapterControlBlock *acb, u_int32_t intmask_org) | |
| 322 | { | |
| 323 | u_int32_t mask; | |
| 324 | ||
| 325 | switch (acb->adapter_type) { | |
| 326 | case ACB_ADAPTER_TYPE_A: { | |
| 327 | /* enable outbound Post Queue, outbound doorbell Interrupt */ | |
| 328 | mask=~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE|ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE|ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE); | |
| 329 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intmask, intmask_org & mask); | |
| 330 | acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff; | |
| 331 | } | |
| 332 | break; | |
| 333 | case ACB_ADAPTER_TYPE_B: { | |
| 334 | /* enable ARCMSR_IOP2DRV_MESSAGE_CMD_DONE */ | |
| 335 | mask=(ARCMSR_IOP2DRV_DATA_WRITE_OK|ARCMSR_IOP2DRV_DATA_READ_OK|ARCMSR_IOP2DRV_CDB_DONE|ARCMSR_IOP2DRV_MESSAGE_CMD_DONE); | |
| 336 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, iop2drv_doorbell_mask, intmask_org | mask); /*1=interrupt enable, 0=interrupt disable*/ | |
| 337 | acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f; | |
| 338 | } | |
| 339 | break; | |
| 340 | case ACB_ADAPTER_TYPE_C: { | |
| 341 | /* enable outbound Post Queue, outbound doorbell Interrupt */ | |
| 342 | mask=~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK); | |
| 343 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, host_int_mask, intmask_org & mask); | |
| 344 | acb->outbound_int_enable= ~(intmask_org & mask) & 0x0000000f; | |
| 345 | } | |
| 346 | break; | |
| 347 | } | |
| 348 | return; | |
| 349 | } | |
| 350 | /* | |
| 351 | ********************************************************************** | |
| 352 | ********************************************************************** | |
| 353 | */ | |
| 354 | static u_int8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb) | |
| 355 | { | |
| 356 | u_int32_t Index; | |
| 357 | u_int8_t Retries=0x00; | |
| 358 | ||
| 359 | do { | |
| 360 | for(Index=0; Index < 100; Index++) { | |
| 361 | if(CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_intstatus) & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { | |
| 362 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intstatus, ARCMSR_MU_OUTBOUND_MESSAGE0_INT);/*clear interrupt*/ | |
| 363 | return TRUE; | |
| 364 | } | |
| 365 | UDELAY(10000); | |
| 366 | }/*max 1 seconds*/ | |
| 367 | }while(Retries++ < 20);/*max 20 sec*/ | |
| 368 | return FALSE; | |
| 369 | } | |
| 370 | /* | |
| 371 | ********************************************************************** | |
| 372 | ********************************************************************** | |
| 373 | */ | |
| 374 | static u_int8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) | |
| 375 | { | |
| 376 | u_int32_t Index; | |
| 377 | u_int8_t Retries=0x00; | |
| 378 | ||
| 379 | do { | |
| 380 | for(Index=0; Index < 100; Index++) { | |
| 381 | if(CHIP_REG_READ32(HBB_DOORBELL, 0, iop2drv_doorbell) & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { | |
| 382 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, iop2drv_doorbell, ARCMSR_MESSAGE_INT_CLEAR_PATTERN);/*clear interrupt*/ | |
| 383 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_DRV2IOP_END_OF_INTERRUPT); | |
| 384 | return TRUE; | |
| 385 | } | |
| 386 | UDELAY(10000); | |
| 387 | }/*max 1 seconds*/ | |
| 388 | }while(Retries++ < 20);/*max 20 sec*/ | |
| 389 | return FALSE; | |
| 390 | } | |
| 391 | /* | |
| 392 | ********************************************************************** | |
| 393 | ********************************************************************** | |
| 394 | */ | |
| 395 | static u_int8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *acb) | |
| 396 | { | |
| 397 | u_int32_t Index; | |
| 398 | u_int8_t Retries=0x00; | |
| 399 | ||
| 400 | do { | |
| 401 | for(Index=0; Index < 100; Index++) { | |
| 402 | if(CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { | |
| 403 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, outbound_doorbell_clear, ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR);/*clear interrupt*/ | |
| 404 | return TRUE; | |
| 405 | } | |
| 406 | UDELAY(10000); | |
| 407 | }/*max 1 seconds*/ | |
| 408 | }while(Retries++ < 20);/*max 20 sec*/ | |
| 409 | return FALSE; | |
| 410 | } | |
| 411 | /* | |
| 412 | ************************************************************************ | |
| 413 | ************************************************************************ | |
| 414 | */ | |
| 415 | static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb) | |
| 416 | { | |
| 417 | int retry_count=30;/* enlarge wait flush adapter cache time: 10 minute */ | |
| 418 | ||
| 419 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_FLUSH_CACHE); | |
| 420 | do { | |
| 421 | if(arcmsr_hba_wait_msgint_ready(acb)) { | |
| 422 | break; | |
| 423 | } else { | |
| 424 | retry_count--; | |
| 425 | } | |
| 426 | }while(retry_count!=0); | |
| 427 | return; | |
| 428 | } | |
| 429 | /* | |
| 430 | ************************************************************************ | |
| 431 | ************************************************************************ | |
| 432 | */ | |
| 433 | static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb) | |
| 434 | { | |
| 435 | int retry_count=30;/* enlarge wait flush adapter cache time: 10 minute */ | |
| 436 | ||
| 437 | CHIP_REG_WRITE32(HBB_DOORBELL, | |
| 438 | 0, drv2iop_doorbell, ARCMSR_MESSAGE_FLUSH_CACHE); | |
| 439 | do { | |
| 440 | if(arcmsr_hbb_wait_msgint_ready(acb)) { | |
| 441 | break; | |
| 442 | } else { | |
| 443 | retry_count--; | |
| 444 | } | |
| 445 | }while(retry_count!=0); | |
| 446 | return; | |
| 447 | } | |
| 448 | /* | |
| 449 | ************************************************************************ | |
| 450 | ************************************************************************ | |
| 451 | */ | |
| 452 | static void arcmsr_flush_hbc_cache(struct AdapterControlBlock *acb) | |
| 453 | { | |
| 454 | int retry_count=30;/* enlarge wait flush adapter cache time: 10 minute */ | |
| 455 | ||
| 456 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_FLUSH_CACHE); | |
| 457 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE); | |
| 458 | do { | |
| 459 | if(arcmsr_hbc_wait_msgint_ready(acb)) { | |
| 460 | break; | |
| 461 | } else { | |
| 462 | retry_count--; | |
| 463 | } | |
| 464 | }while(retry_count!=0); | |
| 465 | return; | |
| 466 | } | |
| 467 | /* | |
| 468 | ************************************************************************ | |
| 469 | ************************************************************************ | |
| 470 | */ | |
| 471 | static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) | |
| 472 | { | |
| 473 | switch (acb->adapter_type) { | |
| 474 | case ACB_ADAPTER_TYPE_A: { | |
| 475 | arcmsr_flush_hba_cache(acb); | |
| 476 | } | |
| 477 | break; | |
| 478 | case ACB_ADAPTER_TYPE_B: { | |
| 479 | arcmsr_flush_hbb_cache(acb); | |
| 480 | } | |
| 481 | break; | |
| 482 | case ACB_ADAPTER_TYPE_C: { | |
| 483 | arcmsr_flush_hbc_cache(acb); | |
| 484 | } | |
| 485 | break; | |
| 486 | } | |
| 487 | return; | |
| 488 | } | |
| 489 | /* | |
| 490 | ******************************************************************************* | |
| 491 | ******************************************************************************* | |
| 492 | */ | |
| 493 | static int arcmsr_suspend(device_t dev) | |
| 494 | { | |
| 495 | struct AdapterControlBlock *acb = device_get_softc(dev); | |
| 496 | ||
| 497 | /* flush controller */ | |
| 498 | arcmsr_iop_parking(acb); | |
| 499 | /* disable all outbound interrupt */ | |
| 500 | arcmsr_disable_allintr(acb); | |
| 501 | return(0); | |
| 502 | } | |
| 503 | /* | |
| 504 | ******************************************************************************* | |
| 505 | ******************************************************************************* | |
| 506 | */ | |
| 507 | static int arcmsr_resume(device_t dev) | |
| 508 | { | |
| 509 | struct AdapterControlBlock *acb = device_get_softc(dev); | |
| 510 | ||
| 511 | arcmsr_iop_init(acb); | |
| 512 | return(0); | |
| 513 | } | |
| 514 | /* | |
| 515 | ********************************************************************************* | |
| 516 | ********************************************************************************* | |
| 517 | */ | |
| 518 | static void arcmsr_async(void *cb_arg, u_int32_t code, struct cam_path *path, void *arg) | |
| 519 | { | |
| 520 | struct AdapterControlBlock *acb; | |
| 521 | u_int8_t target_id, target_lun; | |
| 522 | struct cam_sim * sim; | |
| 523 | ||
| 524 | sim=(struct cam_sim *) cb_arg; | |
| 525 | acb =(struct AdapterControlBlock *) cam_sim_softc(sim); | |
| 526 | switch (code) { | |
| 527 | case AC_LOST_DEVICE: | |
| 528 | target_id=xpt_path_target_id(path); | |
| 529 | target_lun=xpt_path_lun_id(path); | |
| 530 | if((target_id > ARCMSR_MAX_TARGETID) || (target_lun > ARCMSR_MAX_TARGETLUN)) { | |
| 531 | break; | |
| 532 | } | |
| 533 | kprintf("%s:scsi id=%d lun=%d device lost \n", device_get_name(acb->pci_dev), target_id, target_lun); | |
| 534 | break; | |
| 535 | default: | |
| 536 | break; | |
| 537 | } | |
| 538 | } | |
| 539 | /* | |
| 540 | ********************************************************************** | |
| 541 | ********************************************************************** | |
| 542 | */ | |
| 543 | static void arcmsr_srb_complete(struct CommandControlBlock *srb, int stand_flag) | |
| 544 | { | |
| 545 | struct AdapterControlBlock *acb=srb->acb; | |
| 546 | union ccb * pccb=srb->pccb; | |
| 547 | ||
| cc3b439c SW |
548 | if(srb->srb_flags & SRB_FLAG_TIMER_START) |
| 549 | callout_stop(&srb->ccb_callout); | |
| 1901a965 SW |
550 | if((pccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { |
| 551 | bus_dmasync_op_t op; | |
| 552 | ||
| 553 | if((pccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { | |
| 554 | op = BUS_DMASYNC_POSTREAD; | |
| 555 | } else { | |
| 556 | op = BUS_DMASYNC_POSTWRITE; | |
| 557 | } | |
| 558 | bus_dmamap_sync(acb->dm_segs_dmat, srb->dm_segs_dmamap, op); | |
| 559 | bus_dmamap_unload(acb->dm_segs_dmat, srb->dm_segs_dmamap); | |
| 560 | } | |
| 561 | if(stand_flag==1) { | |
| 562 | atomic_subtract_int(&acb->srboutstandingcount, 1); | |
| 563 | if((acb->acb_flags & ACB_F_CAM_DEV_QFRZN) && ( | |
| 564 | acb->srboutstandingcount < ARCMSR_RELEASE_SIMQ_LEVEL)) { | |
| 565 | acb->acb_flags &= ~ACB_F_CAM_DEV_QFRZN; | |
| 566 | pccb->ccb_h.status |= CAM_RELEASE_SIMQ; | |
| 567 | } | |
| 568 | } | |
| cc3b439c SW |
569 | if(srb->srb_state != ARCMSR_SRB_TIMEOUT) |
| 570 | arcmsr_free_srb(srb); | |
| 571 | #ifdef ARCMSR_DEBUG1 | |
| 572 | acb->pktReturnCount++; | |
| 573 | #endif | |
| 1901a965 SW |
574 | xpt_done(pccb); |
| 575 | return; | |
| 576 | } | |
| 577 | /* | |
| 578 | ********************************************************************** | |
| 579 | ********************************************************************** | |
| 580 | */ | |
| 581 | static void arcmsr_report_sense_info(struct CommandControlBlock *srb) | |
| 582 | { | |
| 583 | union ccb * pccb=srb->pccb; | |
| 584 | ||
| 585 | pccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; | |
| 586 | pccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; | |
| 6d4343ee | 587 | if(pccb->csio.sense_len) { |
| 1901a965 SW |
588 | memset(&pccb->csio.sense_data, 0, sizeof(pccb->csio.sense_data)); |
| 589 | memcpy(&pccb->csio.sense_data, srb->arcmsr_cdb.SenseData, | |
| 590 | get_min(sizeof(struct SENSE_DATA), sizeof(pccb->csio.sense_data))); | |
| 591 | ((u_int8_t *)&pccb->csio.sense_data)[0] = (0x1 << 7 | 0x70); /* Valid,ErrorCode */ | |
| 592 | pccb->ccb_h.status |= CAM_AUTOSNS_VALID; | |
| 593 | } | |
| 594 | return; | |
| 595 | } | |
| 596 | /* | |
| 597 | ********************************************************************* | |
| 598 | ********************************************************************* | |
| 599 | */ | |
| 600 | static void arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb) | |
| 601 | { | |
| 602 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_ABORT_CMD); | |
| 603 | if(!arcmsr_hba_wait_msgint_ready(acb)) { | |
| 604 | kprintf("arcmsr%d: wait 'abort all outstanding command' timeout \n", acb->pci_unit); | |
| 605 | } | |
| 606 | return; | |
| 607 | } | |
| 608 | /* | |
| 609 | ********************************************************************* | |
| 610 | ********************************************************************* | |
| 611 | */ | |
| 612 | static void arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb) | |
| 613 | { | |
| 614 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_MESSAGE_ABORT_CMD); | |
| 615 | if(!arcmsr_hbb_wait_msgint_ready(acb)) { | |
| 616 | kprintf("arcmsr%d: wait 'abort all outstanding command' timeout \n", acb->pci_unit); | |
| 617 | } | |
| 618 | return; | |
| 619 | } | |
| 620 | /* | |
| 621 | ********************************************************************* | |
| 622 | ********************************************************************* | |
| 623 | */ | |
| 624 | static void arcmsr_abort_hbc_allcmd(struct AdapterControlBlock *acb) | |
| 625 | { | |
| 626 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_ABORT_CMD); | |
| 627 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE); | |
| 628 | if(!arcmsr_hbc_wait_msgint_ready(acb)) { | |
| 629 | kprintf("arcmsr%d: wait 'abort all outstanding command' timeout \n", acb->pci_unit); | |
| 630 | } | |
| 631 | return; | |
| 632 | } | |
| 633 | /* | |
| 634 | ********************************************************************* | |
| 635 | ********************************************************************* | |
| 636 | */ | |
| 637 | static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb) | |
| 638 | { | |
| 639 | switch (acb->adapter_type) { | |
| 640 | case ACB_ADAPTER_TYPE_A: { | |
| 641 | arcmsr_abort_hba_allcmd(acb); | |
| 642 | } | |
| 643 | break; | |
| 644 | case ACB_ADAPTER_TYPE_B: { | |
| 645 | arcmsr_abort_hbb_allcmd(acb); | |
| 646 | } | |
| 647 | break; | |
| 648 | case ACB_ADAPTER_TYPE_C: { | |
| 649 | arcmsr_abort_hbc_allcmd(acb); | |
| 650 | } | |
| 651 | break; | |
| 652 | } | |
| 653 | return; | |
| 654 | } | |
| 655 | /* | |
| 656 | ************************************************************************** | |
| 657 | ************************************************************************** | |
| 658 | */ | |
| 659 | static void arcmsr_report_srb_state(struct AdapterControlBlock *acb, struct CommandControlBlock *srb, u_int16_t error) | |
| 660 | { | |
| 661 | int target, lun; | |
| 662 | ||
| 663 | target=srb->pccb->ccb_h.target_id; | |
| 664 | lun=srb->pccb->ccb_h.target_lun; | |
| 665 | if(error == FALSE) { | |
| 666 | if(acb->devstate[target][lun]==ARECA_RAID_GONE) { | |
| 667 | acb->devstate[target][lun]=ARECA_RAID_GOOD; | |
| 668 | } | |
| 669 | srb->pccb->ccb_h.status |= CAM_REQ_CMP; | |
| 670 | arcmsr_srb_complete(srb, 1); | |
| 671 | } else { | |
| 672 | switch(srb->arcmsr_cdb.DeviceStatus) { | |
| 673 | case ARCMSR_DEV_SELECT_TIMEOUT: { | |
| 674 | if(acb->devstate[target][lun]==ARECA_RAID_GOOD) { | |
| 675 | kprintf( "arcmsr%d: Target=%x, Lun=%x, selection timeout, raid volume was lost\n", acb->pci_unit, target, lun); | |
| 676 | } | |
| 677 | acb->devstate[target][lun]=ARECA_RAID_GONE; | |
| 678 | srb->pccb->ccb_h.status |= CAM_DEV_NOT_THERE; | |
| 679 | arcmsr_srb_complete(srb, 1); | |
| 680 | } | |
| 681 | break; | |
| 682 | case ARCMSR_DEV_ABORTED: | |
| 683 | case ARCMSR_DEV_INIT_FAIL: { | |
| 684 | acb->devstate[target][lun]=ARECA_RAID_GONE; | |
| 685 | srb->pccb->ccb_h.status |= CAM_DEV_NOT_THERE; | |
| 686 | arcmsr_srb_complete(srb, 1); | |
| 687 | } | |
| 688 | break; | |
| 689 | case SCSISTAT_CHECK_CONDITION: { | |
| 690 | acb->devstate[target][lun]=ARECA_RAID_GOOD; | |
| 691 | arcmsr_report_sense_info(srb); | |
| 692 | arcmsr_srb_complete(srb, 1); | |
| 693 | } | |
| 694 | break; | |
| 695 | default: | |
| 696 | kprintf("arcmsr%d: scsi id=%d lun=%d isr got command error done,but got unknow DeviceStatus=0x%x \n" | |
| 697 | , acb->pci_unit, target, lun ,srb->arcmsr_cdb.DeviceStatus); | |
| 698 | acb->devstate[target][lun]=ARECA_RAID_GONE; | |
| 699 | srb->pccb->ccb_h.status |= CAM_UNCOR_PARITY; | |
| 700 | /*unknow error or crc error just for retry*/ | |
| 701 | arcmsr_srb_complete(srb, 1); | |
| 702 | break; | |
| 703 | } | |
| 704 | } | |
| 705 | return; | |
| 706 | } | |
| 707 | /* | |
| 708 | ************************************************************************** | |
| 709 | ************************************************************************** | |
| 710 | */ | |
| 711 | static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, u_int32_t flag_srb, u_int16_t error) | |
| 712 | { | |
| 713 | struct CommandControlBlock *srb; | |
| 714 | ||
| 715 | /* check if command done with no error*/ | |
| 716 | switch (acb->adapter_type) { | |
| 717 | case ACB_ADAPTER_TYPE_C: | |
| cc3b439c | 718 | srb = (struct CommandControlBlock *)(acb->vir2phy_offset+(flag_srb & 0xFFFFFFE0));/*frame must be 32 bytes aligned*/ |
| 1901a965 SW |
719 | break; |
| 720 | case ACB_ADAPTER_TYPE_A: | |
| 721 | case ACB_ADAPTER_TYPE_B: | |
| 722 | default: | |
| 723 | srb = (struct CommandControlBlock *)(acb->vir2phy_offset+(flag_srb << 5));/*frame must be 32 bytes aligned*/ | |
| 724 | break; | |
| 725 | } | |
| cc3b439c SW |
726 | if((srb->acb!=acb) || (srb->srb_state!=ARCMSR_SRB_START)) { |
| 727 | if(srb->srb_state == ARCMSR_SRB_TIMEOUT) { | |
| 728 | arcmsr_free_srb(srb); | |
| 729 | kprintf("arcmsr%d: srb='%p' return srb has been timeouted\n", acb->pci_unit, srb); | |
| 1901a965 SW |
730 | return; |
| 731 | } | |
| cc3b439c SW |
732 | kprintf("arcmsr%d: return srb has been completed\n" |
| 733 | "srb='%p' srb_state=0x%x outstanding srb count=%d \n", | |
| 734 | acb->pci_unit, srb, srb->srb_state, acb->srboutstandingcount); | |
| 1901a965 SW |
735 | return; |
| 736 | } | |
| 737 | arcmsr_report_srb_state(acb, srb, error); | |
| 738 | return; | |
| 739 | } | |
| 740 | /* | |
| cc3b439c SW |
741 | ************************************************************************** |
| 742 | ************************************************************************** | |
| 743 | */ | |
| 744 | static void arcmsr_srb_timeout(void* arg) | |
| 745 | { | |
| 746 | struct CommandControlBlock *srb = (struct CommandControlBlock *)arg; | |
| 747 | struct AdapterControlBlock *acb; | |
| 748 | int target, lun; | |
| 749 | u_int8_t cmd; | |
| 750 | ||
| 751 | target=srb->pccb->ccb_h.target_id; | |
| 752 | lun=srb->pccb->ccb_h.target_lun; | |
| 753 | acb = srb->acb; | |
| 754 | ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); | |
| 755 | if(srb->srb_state == ARCMSR_SRB_START) | |
| 756 | { | |
| 757 | cmd = srb->pccb->csio.cdb_io.cdb_bytes[0]; | |
| 758 | srb->srb_state = ARCMSR_SRB_TIMEOUT; | |
| 759 | srb->pccb->ccb_h.status |= CAM_CMD_TIMEOUT; | |
| 760 | arcmsr_srb_complete(srb, 1); | |
| 761 | kprintf("arcmsr%d: scsi id %d lun %d cmd=0x%x srb='%p' ccb command time out!\n", | |
| 762 | acb->pci_unit, target, lun, cmd, srb); | |
| 763 | } | |
| 764 | ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); | |
| 765 | #ifdef ARCMSR_DEBUG1 | |
| 766 | arcmsr_dump_data(acb); | |
| 767 | #endif | |
| 768 | } | |
| 769 | ||
| 770 | /* | |
| 1901a965 SW |
771 | ********************************************************************** |
| 772 | ********************************************************************** | |
| 773 | */ | |
| 774 | static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) | |
| 775 | { | |
| 776 | int i=0; | |
| 777 | u_int32_t flag_srb; | |
| 778 | u_int16_t error; | |
| 779 | ||
| 780 | switch (acb->adapter_type) { | |
| 781 | case ACB_ADAPTER_TYPE_A: { | |
| 782 | u_int32_t outbound_intstatus; | |
| 783 | ||
| 784 | /*clear and abort all outbound posted Q*/ | |
| 785 | outbound_intstatus=CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_intstatus) & acb->outbound_int_enable; | |
| 786 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intstatus, outbound_intstatus);/*clear interrupt*/ | |
| 787 | while(((flag_srb=CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_queueport)) != 0xFFFFFFFF) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { | |
| 788 | error=(flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE0)?TRUE:FALSE; | |
| 789 | arcmsr_drain_donequeue(acb, flag_srb, error); | |
| 790 | } | |
| 791 | } | |
| 792 | break; | |
| 793 | case ACB_ADAPTER_TYPE_B: { | |
| 794 | struct HBB_MessageUnit *phbbmu=(struct HBB_MessageUnit *)acb->pmu; | |
| 795 | ||
| 796 | /*clear all outbound posted Q*/ | |
| 797 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, iop2drv_doorbell, ARCMSR_DOORBELL_INT_CLEAR_PATTERN); /* clear doorbell interrupt */ | |
| 798 | for(i=0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) { | |
| 799 | if((flag_srb=phbbmu->done_qbuffer[i])!=0) { | |
| 800 | phbbmu->done_qbuffer[i]=0; | |
| 801 | error=(flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE0)?TRUE:FALSE; | |
| 802 | arcmsr_drain_donequeue(acb, flag_srb, error); | |
| 803 | } | |
| 804 | phbbmu->post_qbuffer[i]=0; | |
| 805 | }/*drain reply FIFO*/ | |
| 806 | phbbmu->doneq_index=0; | |
| 807 | phbbmu->postq_index=0; | |
| 808 | } | |
| 809 | break; | |
| 810 | case ACB_ADAPTER_TYPE_C: { | |
| 811 | ||
| 812 | while((CHIP_REG_READ32(HBC_MessageUnit, 0, host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { | |
| 813 | flag_srb=CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_queueport_low); | |
| 814 | error=(flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE1)?TRUE:FALSE; | |
| 815 | arcmsr_drain_donequeue(acb, flag_srb, error); | |
| 816 | } | |
| 817 | } | |
| 818 | break; | |
| 819 | } | |
| 820 | return; | |
| 821 | } | |
| 822 | /* | |
| 823 | **************************************************************************** | |
| 824 | **************************************************************************** | |
| 825 | */ | |
| 826 | static void arcmsr_iop_reset(struct AdapterControlBlock *acb) | |
| 827 | { | |
| 828 | struct CommandControlBlock *srb; | |
| 829 | u_int32_t intmask_org; | |
| 830 | u_int32_t i=0; | |
| 831 | ||
| 832 | if(acb->srboutstandingcount>0) { | |
| 833 | /* disable all outbound interrupt */ | |
| 834 | intmask_org=arcmsr_disable_allintr(acb); | |
| 835 | /*clear and abort all outbound posted Q*/ | |
| 836 | arcmsr_done4abort_postqueue(acb); | |
| 837 | /* talk to iop 331 outstanding command aborted*/ | |
| 838 | arcmsr_abort_allcmd(acb); | |
| 839 | for(i=0;i<ARCMSR_MAX_FREESRB_NUM;i++) { | |
| 840 | srb=acb->psrb_pool[i]; | |
| cc3b439c SW |
841 | if(srb->srb_state==ARCMSR_SRB_START) { |
| 842 | srb->srb_state=ARCMSR_SRB_ABORTED; | |
| 1901a965 SW |
843 | srb->pccb->ccb_h.status |= CAM_REQ_ABORTED; |
| 844 | arcmsr_srb_complete(srb, 1); | |
| cc3b439c SW |
845 | kprintf("arcmsr%d: scsi id=%d lun=%d srb='%p' aborted\n" |
| 846 | , acb->pci_unit, srb->pccb->ccb_h.target_id | |
| 847 | , srb->pccb->ccb_h.target_lun, srb); | |
| 1901a965 SW |
848 | } |
| 849 | } | |
| 850 | /* enable all outbound interrupt */ | |
| 851 | arcmsr_enable_allintr(acb, intmask_org); | |
| 852 | } | |
| cc3b439c | 853 | acb->srboutstandingcount=0; |
| 1901a965 SW |
854 | acb->workingsrb_doneindex=0; |
| 855 | acb->workingsrb_startindex=0; | |
| cc3b439c SW |
856 | #ifdef ARCMSR_DEBUG1 |
| 857 | acb->pktRequestCount = 0; | |
| 858 | acb->pktReturnCount = 0; | |
| 859 | #endif | |
| 1901a965 SW |
860 | return; |
| 861 | } | |
| 862 | /* | |
| 863 | ********************************************************************** | |
| 864 | ********************************************************************** | |
| 865 | */ | |
| 866 | static void arcmsr_build_srb(struct CommandControlBlock *srb, | |
| 867 | bus_dma_segment_t *dm_segs, u_int32_t nseg) | |
| 868 | { | |
| 869 | struct ARCMSR_CDB * arcmsr_cdb= &srb->arcmsr_cdb; | |
| 870 | u_int8_t * psge=(u_int8_t *)&arcmsr_cdb->u; | |
| 871 | u_int32_t address_lo, address_hi; | |
| 872 | union ccb * pccb=srb->pccb; | |
| 873 | struct ccb_scsiio * pcsio= &pccb->csio; | |
| 874 | u_int32_t arccdbsize=0x30; | |
| 875 | ||
| 876 | memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB)); | |
| 877 | arcmsr_cdb->Bus=0; | |
| 878 | arcmsr_cdb->TargetID=pccb->ccb_h.target_id; | |
| 879 | arcmsr_cdb->LUN=pccb->ccb_h.target_lun; | |
| 880 | arcmsr_cdb->Function=1; | |
| 881 | arcmsr_cdb->CdbLength=(u_int8_t)pcsio->cdb_len; | |
| 882 | arcmsr_cdb->Context=0; | |
| 883 | bcopy(pcsio->cdb_io.cdb_bytes, arcmsr_cdb->Cdb, pcsio->cdb_len); | |
| 884 | if(nseg != 0) { | |
| 885 | struct AdapterControlBlock *acb=srb->acb; | |
| 886 | bus_dmasync_op_t op; | |
| 887 | u_int32_t length, i, cdb_sgcount=0; | |
| 888 | ||
| 889 | if((pccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { | |
| 890 | op=BUS_DMASYNC_PREREAD; | |
| 891 | } else { | |
| 892 | op=BUS_DMASYNC_PREWRITE; | |
| 893 | arcmsr_cdb->Flags|=ARCMSR_CDB_FLAG_WRITE; | |
| 894 | srb->srb_flags|=SRB_FLAG_WRITE; | |
| 895 | } | |
| 896 | bus_dmamap_sync(acb->dm_segs_dmat, srb->dm_segs_dmamap, op); | |
| 897 | for(i=0;i<nseg;i++) { | |
| 898 | /* Get the physical address of the current data pointer */ | |
| 899 | length=arcmsr_htole32(dm_segs[i].ds_len); | |
| 900 | address_lo=arcmsr_htole32(dma_addr_lo32(dm_segs[i].ds_addr)); | |
| 901 | address_hi=arcmsr_htole32(dma_addr_hi32(dm_segs[i].ds_addr)); | |
| 902 | if(address_hi==0) { | |
| 903 | struct SG32ENTRY * pdma_sg=(struct SG32ENTRY *)psge; | |
| 904 | pdma_sg->address=address_lo; | |
| 905 | pdma_sg->length=length; | |
| 906 | psge += sizeof(struct SG32ENTRY); | |
| 907 | arccdbsize += sizeof(struct SG32ENTRY); | |
| 908 | } else { | |
| 909 | u_int32_t sg64s_size=0, tmplength=length; | |
| 910 | ||
| 911 | while(1) { | |
| 912 | u_int64_t span4G, length0; | |
| 913 | struct SG64ENTRY * pdma_sg=(struct SG64ENTRY *)psge; | |
| 914 | ||
| 915 | span4G=(u_int64_t)address_lo + tmplength; | |
| 916 | pdma_sg->addresshigh=address_hi; | |
| 917 | pdma_sg->address=address_lo; | |
| 918 | if(span4G > 0x100000000) { | |
| 919 | /*see if cross 4G boundary*/ | |
| 920 | length0=0x100000000-address_lo; | |
| 921 | pdma_sg->length=(u_int32_t)length0|IS_SG64_ADDR; | |
| 922 | address_hi=address_hi+1; | |
| 923 | address_lo=0; | |
| 924 | tmplength=tmplength-(u_int32_t)length0; | |
| 925 | sg64s_size += sizeof(struct SG64ENTRY); | |
| 926 | psge += sizeof(struct SG64ENTRY); | |
| 927 | cdb_sgcount++; | |
| 928 | } else { | |
| 929 | pdma_sg->length=tmplength|IS_SG64_ADDR; | |
| 930 | sg64s_size += sizeof(struct SG64ENTRY); | |
| 931 | psge += sizeof(struct SG64ENTRY); | |
| 932 | break; | |
| 933 | } | |
| 934 | } | |
| 935 | arccdbsize += sg64s_size; | |
| 936 | } | |
| 937 | cdb_sgcount++; | |
| 938 | } | |
| 939 | arcmsr_cdb->sgcount=(u_int8_t)cdb_sgcount; | |
| 940 | arcmsr_cdb->DataLength=pcsio->dxfer_len; | |
| 941 | if( arccdbsize > 256) { | |
| 942 | arcmsr_cdb->Flags|=ARCMSR_CDB_FLAG_SGL_BSIZE; | |
| 943 | } | |
| 944 | } else { | |
| 945 | arcmsr_cdb->DataLength = 0; | |
| 946 | } | |
| 947 | srb->arc_cdb_size=arccdbsize; | |
| 948 | return; | |
| 949 | } | |
| 950 | /* | |
| 951 | ************************************************************************** | |
| 952 | ************************************************************************** | |
| 953 | */ | |
| 954 | static void arcmsr_post_srb(struct AdapterControlBlock *acb, struct CommandControlBlock *srb) | |
| 955 | { | |
| 956 | u_int32_t cdb_shifted_phyaddr=(u_int32_t) srb->cdb_shifted_phyaddr; | |
| 957 | struct ARCMSR_CDB * arcmsr_cdb=(struct ARCMSR_CDB *)&srb->arcmsr_cdb; | |
| 958 | ||
| 959 | bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, (srb->srb_flags & SRB_FLAG_WRITE) ? BUS_DMASYNC_POSTWRITE:BUS_DMASYNC_POSTREAD); | |
| 960 | atomic_add_int(&acb->srboutstandingcount, 1); | |
| cc3b439c | 961 | srb->srb_state=ARCMSR_SRB_START; |
| 1901a965 SW |
962 | |
| 963 | switch (acb->adapter_type) { | |
| 964 | case ACB_ADAPTER_TYPE_A: { | |
| 965 | if(arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { | |
| 966 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_queueport, cdb_shifted_phyaddr|ARCMSR_SRBPOST_FLAG_SGL_BSIZE); | |
| 967 | } else { | |
| 968 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_queueport, cdb_shifted_phyaddr); | |
| 969 | } | |
| 970 | } | |
| 971 | break; | |
| 972 | case ACB_ADAPTER_TYPE_B: { | |
| 973 | struct HBB_MessageUnit *phbbmu=(struct HBB_MessageUnit *)acb->pmu; | |
| 974 | int ending_index, index; | |
| 975 | ||
| 976 | index=phbbmu->postq_index; | |
| 977 | ending_index=((index+1)%ARCMSR_MAX_HBB_POSTQUEUE); | |
| 978 | phbbmu->post_qbuffer[ending_index]=0; | |
| 979 | if(arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { | |
| 980 | phbbmu->post_qbuffer[index]= cdb_shifted_phyaddr|ARCMSR_SRBPOST_FLAG_SGL_BSIZE; | |
| 981 | } else { | |
| 982 | phbbmu->post_qbuffer[index]= cdb_shifted_phyaddr; | |
| 983 | } | |
| 984 | index++; | |
| 985 | index %= ARCMSR_MAX_HBB_POSTQUEUE; /*if last index number set it to 0 */ | |
| 986 | phbbmu->postq_index=index; | |
| 987 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_DRV2IOP_CDB_POSTED); | |
| 988 | } | |
| 989 | break; | |
| 990 | case ACB_ADAPTER_TYPE_C: | |
| 991 | { | |
| 992 | u_int32_t ccb_post_stamp, arc_cdb_size, cdb_phyaddr_hi32; | |
| 993 | ||
| 994 | arc_cdb_size=(srb->arc_cdb_size>0x300)?0x300:srb->arc_cdb_size; | |
| 995 | ccb_post_stamp=(cdb_shifted_phyaddr | ((arc_cdb_size-1) >> 6) | 1); | |
| 996 | cdb_phyaddr_hi32 = acb->srb_phyaddr.B.phyadd_high; | |
| 997 | if(cdb_phyaddr_hi32) | |
| 998 | { | |
| 999 | CHIP_REG_WRITE32(HBC_MessageUnit,0,inbound_queueport_high, cdb_phyaddr_hi32); | |
| 1000 | CHIP_REG_WRITE32(HBC_MessageUnit,0,inbound_queueport_low, ccb_post_stamp); | |
| 1001 | } | |
| 1002 | else | |
| 1003 | { | |
| 1004 | CHIP_REG_WRITE32(HBC_MessageUnit,0,inbound_queueport_low, ccb_post_stamp); | |
| 1005 | } | |
| 95696aa4 SW |
1006 | } |
| 1007 | break; | |
| 1901a965 SW |
1008 | } |
| 1009 | return; | |
| 1010 | } | |
| 1011 | /* | |
| 1012 | ************************************************************************ | |
| 1013 | ************************************************************************ | |
| 1014 | */ | |
| 1015 | static struct QBUFFER * arcmsr_get_iop_rqbuffer( struct AdapterControlBlock *acb) | |
| 1016 | { | |
| 1017 | struct QBUFFER *qbuffer=NULL; | |
| 1018 | ||
| 1019 | switch (acb->adapter_type) { | |
| 1020 | case ACB_ADAPTER_TYPE_A: { | |
| 1021 | struct HBA_MessageUnit *phbamu=(struct HBA_MessageUnit *)acb->pmu; | |
| 1022 | ||
| 1023 | qbuffer=(struct QBUFFER *)&phbamu->message_rbuffer; | |
| 1024 | } | |
| 1025 | break; | |
| 1026 | case ACB_ADAPTER_TYPE_B: { | |
| 1027 | struct HBB_MessageUnit *phbbmu=(struct HBB_MessageUnit *)acb->pmu; | |
| 1028 | ||
| 1029 | qbuffer=(struct QBUFFER *)&phbbmu->hbb_rwbuffer->message_rbuffer; | |
| 1030 | } | |
| 1031 | break; | |
| 1032 | case ACB_ADAPTER_TYPE_C: { | |
| 1033 | struct HBC_MessageUnit *phbcmu=(struct HBC_MessageUnit *)acb->pmu; | |
| 1034 | ||
| 1035 | qbuffer=(struct QBUFFER *)&phbcmu->message_rbuffer; | |
| 1036 | } | |
| 1037 | break; | |
| 1038 | } | |
| 1039 | return(qbuffer); | |
| 1040 | } | |
| 1041 | /* | |
| 1042 | ************************************************************************ | |
| 1043 | ************************************************************************ | |
| 1044 | */ | |
| 1045 | static struct QBUFFER * arcmsr_get_iop_wqbuffer( struct AdapterControlBlock *acb) | |
| 1046 | { | |
| 1047 | struct QBUFFER *qbuffer=NULL; | |
| 1048 | ||
| 1049 | switch (acb->adapter_type) { | |
| 1050 | case ACB_ADAPTER_TYPE_A: { | |
| 1051 | struct HBA_MessageUnit *phbamu=(struct HBA_MessageUnit *)acb->pmu; | |
| 1052 | ||
| 1053 | qbuffer=(struct QBUFFER *)&phbamu->message_wbuffer; | |
| 1054 | } | |
| 1055 | break; | |
| 1056 | case ACB_ADAPTER_TYPE_B: { | |
| 1057 | struct HBB_MessageUnit *phbbmu=(struct HBB_MessageUnit *)acb->pmu; | |
| 1058 | ||
| 1059 | qbuffer=(struct QBUFFER *)&phbbmu->hbb_rwbuffer->message_wbuffer; | |
| 1060 | } | |
| 1061 | break; | |
| 1062 | case ACB_ADAPTER_TYPE_C: { | |
| 1063 | struct HBC_MessageUnit *phbcmu=(struct HBC_MessageUnit *)acb->pmu; | |
| 1064 | ||
| 1065 | qbuffer=(struct QBUFFER *)&phbcmu->message_wbuffer; | |
| 1066 | } | |
| 1067 | break; | |
| 1068 | } | |
| 1069 | return(qbuffer); | |
| 1070 | } | |
| 1071 | /* | |
| 1072 | ************************************************************************** | |
| 1073 | ************************************************************************** | |
| 1074 | */ | |
| 1075 | static void arcmsr_iop_message_read(struct AdapterControlBlock *acb) | |
| 1076 | { | |
| 1077 | switch (acb->adapter_type) { | |
| 1078 | case ACB_ADAPTER_TYPE_A: { | |
| 1079 | /* let IOP know data has been read */ | |
| 1080 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_READ_OK); | |
| 1081 | } | |
| 1082 | break; | |
| 1083 | case ACB_ADAPTER_TYPE_B: { | |
| 1084 | /* let IOP know data has been read */ | |
| 1085 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_DRV2IOP_DATA_READ_OK); | |
| 1086 | } | |
| 1087 | break; | |
| 1088 | case ACB_ADAPTER_TYPE_C: { | |
| 1089 | /* let IOP know data has been read */ | |
| 1090 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK); | |
| 1091 | } | |
| 1092 | } | |
| 1093 | return; | |
| 1094 | } | |
| 1095 | /* | |
| 1096 | ************************************************************************** | |
| 1097 | ************************************************************************** | |
| 1098 | */ | |
| 1099 | static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb) | |
| 1100 | { | |
| 1101 | switch (acb->adapter_type) { | |
| 1102 | case ACB_ADAPTER_TYPE_A: { | |
| 1103 | /* | |
| 1104 | ** push inbound doorbell tell iop, driver data write ok | |
| 1105 | ** and wait reply on next hwinterrupt for next Qbuffer post | |
| 1106 | */ | |
| 1107 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK); | |
| 1108 | } | |
| 1109 | break; | |
| 1110 | case ACB_ADAPTER_TYPE_B: { | |
| 1111 | /* | |
| 1112 | ** push inbound doorbell tell iop, driver data write ok | |
| 1113 | ** and wait reply on next hwinterrupt for next Qbuffer post | |
| 1114 | */ | |
| 1115 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_DRV2IOP_DATA_WRITE_OK); | |
| 1116 | } | |
| 1117 | break; | |
| 1118 | case ACB_ADAPTER_TYPE_C: { | |
| 1119 | /* | |
| 1120 | ** push inbound doorbell tell iop, driver data write ok | |
| 1121 | ** and wait reply on next hwinterrupt for next Qbuffer post | |
| 1122 | */ | |
| 1123 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK); | |
| 1124 | } | |
| 1125 | break; | |
| 1126 | } | |
| 1127 | } | |
| 1128 | /* | |
| 1129 | ********************************************************************** | |
| 1130 | ********************************************************************** | |
| 1131 | */ | |
| 1132 | static void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb) | |
| 1133 | { | |
| 1134 | u_int8_t *pQbuffer; | |
| 1135 | struct QBUFFER *pwbuffer; | |
| 1136 | u_int8_t * iop_data; | |
| 1137 | int32_t allxfer_len=0; | |
| 1138 | ||
| 1139 | pwbuffer=arcmsr_get_iop_wqbuffer(acb); | |
| 1140 | iop_data=(u_int8_t *)pwbuffer->data; | |
| 1141 | if(acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READ) { | |
| 1142 | acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READ); | |
| 1143 | while((acb->wqbuf_firstindex!=acb->wqbuf_lastindex) | |
| 1144 | && (allxfer_len<124)) { | |
| 1145 | pQbuffer=&acb->wqbuffer[acb->wqbuf_firstindex]; | |
| 1146 | memcpy(iop_data, pQbuffer, 1); | |
| 1147 | acb->wqbuf_firstindex++; | |
| 1148 | acb->wqbuf_firstindex %=ARCMSR_MAX_QBUFFER; /*if last index number set it to 0 */ | |
| 1149 | iop_data++; | |
| 1150 | allxfer_len++; | |
| 1151 | } | |
| 1152 | pwbuffer->data_len=allxfer_len; | |
| 1153 | /* | |
| 1154 | ** push inbound doorbell and wait reply at hwinterrupt routine for next Qbuffer post | |
| 1155 | */ | |
| 1156 | arcmsr_iop_message_wrote(acb); | |
| 1157 | } | |
| 1158 | return; | |
| 1159 | } | |
| 1160 | /* | |
| 1161 | ************************************************************************ | |
| 1162 | ************************************************************************ | |
| 1163 | */ | |
| 1164 | static void arcmsr_stop_hba_bgrb(struct AdapterControlBlock *acb) | |
| 1165 | { | |
| 1166 | acb->acb_flags &=~ACB_F_MSG_START_BGRB; | |
| 1167 | CHIP_REG_WRITE32(HBA_MessageUnit, | |
| 1168 | 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_STOP_BGRB); | |
| 1169 | if(!arcmsr_hba_wait_msgint_ready(acb)) { | |
| 1170 | kprintf("arcmsr%d: wait 'stop adapter background rebulid' timeout \n" | |
| 1171 | , acb->pci_unit); | |
| 1172 | } | |
| 1173 | return; | |
| 1174 | } | |
| 1175 | /* | |
| 1176 | ************************************************************************ | |
| 1177 | ************************************************************************ | |
| 1178 | */ | |
| 1179 | static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb) | |
| 1180 | { | |
| 1181 | acb->acb_flags &= ~ACB_F_MSG_START_BGRB; | |
| 1182 | CHIP_REG_WRITE32(HBB_DOORBELL, | |
| 1183 | 0, drv2iop_doorbell, ARCMSR_MESSAGE_STOP_BGRB); | |
| 1184 | if(!arcmsr_hbb_wait_msgint_ready(acb)) { | |
| 1185 | kprintf( "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" | |
| 1186 | , acb->pci_unit); | |
| 1187 | } | |
| 1188 | return; | |
| 1189 | } | |
| 1190 | /* | |
| 1191 | ************************************************************************ | |
| 1192 | ************************************************************************ | |
| 1193 | */ | |
| 1194 | static void arcmsr_stop_hbc_bgrb(struct AdapterControlBlock *acb) | |
| 1195 | { | |
| 1196 | acb->acb_flags &=~ACB_F_MSG_START_BGRB; | |
| 1197 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_STOP_BGRB); | |
| 1198 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell,ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE); | |
| 1199 | if(!arcmsr_hbc_wait_msgint_ready(acb)) { | |
| 1200 | kprintf("arcmsr%d: wait 'stop adapter background rebulid' timeout \n", acb->pci_unit); | |
| 1201 | } | |
| 1202 | return; | |
| 1203 | } | |
| 1204 | /* | |
| 1205 | ************************************************************************ | |
| 1206 | ************************************************************************ | |
| 1207 | */ | |
| 1208 | static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) | |
| 1209 | { | |
| 1210 | switch (acb->adapter_type) { | |
| 1211 | case ACB_ADAPTER_TYPE_A: { | |
| 1212 | arcmsr_stop_hba_bgrb(acb); | |
| 1213 | } | |
| 1214 | break; | |
| 1215 | case ACB_ADAPTER_TYPE_B: { | |
| 1216 | arcmsr_stop_hbb_bgrb(acb); | |
| 1217 | } | |
| 1218 | break; | |
| 1219 | case ACB_ADAPTER_TYPE_C: { | |
| 1220 | arcmsr_stop_hbc_bgrb(acb); | |
| 1221 | } | |
| 1222 | break; | |
| 1223 | } | |
| 1224 | return; | |
| 1225 | } | |
| 1226 | /* | |
| 1227 | ************************************************************************ | |
| 1228 | ************************************************************************ | |
| 1229 | */ | |
| 1230 | static void arcmsr_poll(struct cam_sim * psim) | |
| 1231 | { | |
| 1232 | struct AdapterControlBlock *acb; | |
| cc3b439c | 1233 | int mutex; |
| 1901a965 SW |
1234 | |
| 1235 | acb = (struct AdapterControlBlock *)cam_sim_softc(psim); | |
| cc3b439c SW |
1236 | mutex = lockstatus(&acb->qbuffer_lock, curthread); |
| 1237 | if( mutex == 0 ) | |
| 1238 | ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); | |
| 1901a965 | 1239 | arcmsr_interrupt(acb); |
| cc3b439c SW |
1240 | if( mutex == 0 ) |
| 1241 | ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); | |
| 1901a965 SW |
1242 | return; |
| 1243 | } | |
| 1244 | /* | |
| 1245 | ************************************************************************** | |
| 1246 | ************************************************************************** | |
| 1247 | */ | |
| 1248 | static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb) | |
| 1249 | { | |
| 1250 | struct QBUFFER *prbuffer; | |
| 1251 | u_int8_t *pQbuffer; | |
| 1252 | u_int8_t *iop_data; | |
| 1253 | int my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex; | |
| 1254 | ||
| 1255 | /*check this iop data if overflow my rqbuffer*/ | |
| 1256 | rqbuf_lastindex=acb->rqbuf_lastindex; | |
| 1257 | rqbuf_firstindex=acb->rqbuf_firstindex; | |
| 1258 | prbuffer=arcmsr_get_iop_rqbuffer(acb); | |
| 1259 | iop_data=(u_int8_t *)prbuffer->data; | |
| 1260 | iop_len=prbuffer->data_len; | |
| 1261 | my_empty_len=(rqbuf_firstindex-rqbuf_lastindex-1)&(ARCMSR_MAX_QBUFFER-1); | |
| 1262 | if(my_empty_len>=iop_len) { | |
| 1263 | while(iop_len > 0) { | |
| 1264 | pQbuffer=&acb->rqbuffer[rqbuf_lastindex]; | |
| 1265 | memcpy(pQbuffer, iop_data, 1); | |
| 1266 | rqbuf_lastindex++; | |
| 1267 | rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;/*if last index number set it to 0 */ | |
| 1268 | iop_data++; | |
| 1269 | iop_len--; | |
| 1270 | } | |
| 1271 | acb->rqbuf_lastindex=rqbuf_lastindex; | |
| 1272 | arcmsr_iop_message_read(acb); | |
| 1273 | /*signature, let IOP know data has been read */ | |
| 1274 | } else { | |
| 1275 | acb->acb_flags|=ACB_F_IOPDATA_OVERFLOW; | |
| 1276 | } | |
| 1277 | return; | |
| 1278 | } | |
| 1279 | /* | |
| 1280 | ************************************************************************** | |
| 1281 | ************************************************************************** | |
| 1282 | */ | |
| 1283 | static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb) | |
| 1284 | { | |
| 1285 | acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READ; | |
| 1286 | /* | |
| 1287 | ***************************************************************** | |
| 1288 | ** check if there are any mail packages from user space program | |
| 1289 | ** in my post bag, now is the time to send them into Areca's firmware | |
| 1290 | ***************************************************************** | |
| 1291 | */ | |
| 1292 | if(acb->wqbuf_firstindex!=acb->wqbuf_lastindex) { | |
| 1293 | u_int8_t *pQbuffer; | |
| 1294 | struct QBUFFER *pwbuffer; | |
| 1295 | u_int8_t *iop_data; | |
| 1296 | int allxfer_len=0; | |
| 1297 | ||
| 1298 | acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READ); | |
| 1299 | pwbuffer=arcmsr_get_iop_wqbuffer(acb); | |
| 1300 | iop_data=(u_int8_t *)pwbuffer->data; | |
| 1301 | while((acb->wqbuf_firstindex!=acb->wqbuf_lastindex) | |
| 1302 | && (allxfer_len<124)) { | |
| 1303 | pQbuffer=&acb->wqbuffer[acb->wqbuf_firstindex]; | |
| 1304 | memcpy(iop_data, pQbuffer, 1); | |
| 1305 | acb->wqbuf_firstindex++; | |
| 1306 | acb->wqbuf_firstindex %=ARCMSR_MAX_QBUFFER; /*if last index number set it to 0 */ | |
| 1307 | iop_data++; | |
| 1308 | allxfer_len++; | |
| 1309 | } | |
| 1310 | pwbuffer->data_len=allxfer_len; | |
| 1311 | /* | |
| 1312 | ** push inbound doorbell tell iop driver data write ok | |
| 1313 | ** and wait reply on next hwinterrupt for next Qbuffer post | |
| 1314 | */ | |
| 1315 | arcmsr_iop_message_wrote(acb); | |
| 1316 | } | |
| 1317 | if(acb->wqbuf_firstindex==acb->wqbuf_lastindex) { | |
| 1318 | acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED; | |
| 1319 | } | |
| 1320 | return; | |
| 1321 | } | |
| 1322 | ||
| 1323 | static void arcmsr_rescanLun_cb(struct cam_periph *periph, union ccb *ccb) | |
| 1324 | { | |
| 1325 | /* | |
| 1326 | if (ccb->ccb_h.status != CAM_REQ_CMP) | |
| 1327 | kprintf("arcmsr_rescanLun_cb: Rescan Target=%x, lun=%x, failure status=%x\n",ccb->ccb_h.target_id,ccb->ccb_h.target_lun,ccb->ccb_h.status); | |
| 1328 | else | |
| 1329 | kprintf("arcmsr_rescanLun_cb: Rescan lun successfully!\n"); | |
| 1330 | */ | |
| 1331 | xpt_free_path(ccb->ccb_h.path); | |
| 1332 | } | |
| 1333 | ||
| 1334 | static void arcmsr_rescan_lun(struct AdapterControlBlock *acb, int target, int lun) | |
| 1335 | { | |
| 1336 | struct cam_path *path; | |
| 1337 | union ccb ccb; | |
| 1338 | ||
| 1339 | if (xpt_create_path(&path, xpt_periph, cam_sim_path(acb->psim), target, lun) != CAM_REQ_CMP) | |
| 1340 | return; | |
| 1341 | /* kprintf("arcmsr_rescan_lun: Rescan Target=%x, Lun=%x\n", target, lun); */ | |
| 1342 | bzero(&ccb, sizeof(union ccb)); | |
| 1343 | xpt_setup_ccb(&ccb.ccb_h, path, 5); | |
| 1344 | ccb.ccb_h.func_code = XPT_SCAN_LUN; | |
| 1345 | ccb.ccb_h.cbfcnp = arcmsr_rescanLun_cb; | |
| 1346 | ccb.crcn.flags = CAM_FLAG_NONE; | |
| 1347 | xpt_action(&ccb); | |
| 1348 | return; | |
| 1349 | } | |
| 1350 | ||
| 1351 | ||
| 1352 | static void arcmsr_abort_dr_ccbs(struct AdapterControlBlock *acb, int target, int lun) | |
| 1353 | { | |
| 1354 | struct CommandControlBlock *srb; | |
| 1355 | u_int32_t intmask_org; | |
| 1356 | int i; | |
| 1357 | ||
| 1358 | ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); | |
| 1359 | /* disable all outbound interrupts */ | |
| 1360 | intmask_org = arcmsr_disable_allintr(acb); | |
| 1361 | for (i = 0; i < ARCMSR_MAX_FREESRB_NUM; i++) | |
| 1362 | { | |
| 1363 | srb = acb->psrb_pool[i]; | |
| cc3b439c | 1364 | if (srb->srb_state == ARCMSR_SRB_START) |
| 1901a965 SW |
1365 | { |
| 1366 | if((target == srb->pccb->ccb_h.target_id) && (lun == srb->pccb->ccb_h.target_lun)) | |
| 1367 | { | |
| cc3b439c | 1368 | srb->srb_state = ARCMSR_SRB_ABORTED; |
| 1901a965 SW |
1369 | srb->pccb->ccb_h.status |= CAM_REQ_ABORTED; |
| 1370 | arcmsr_srb_complete(srb, 1); | |
| cc3b439c | 1371 | kprintf("arcmsr%d: abort scsi id %d lun %d srb=%p \n", acb->pci_unit, target, lun, srb); |
| 1901a965 SW |
1372 | } |
| 1373 | } | |
| 1374 | } | |
| 1375 | /* enable outbound Post Queue, outbound doorbell Interrupt */ | |
| 1376 | arcmsr_enable_allintr(acb, intmask_org); | |
| 1377 | ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); | |
| 1378 | } | |
| 1379 | ||
| 1380 | ||
| 1381 | /* | |
| 1382 | ************************************************************************** | |
| 1383 | ************************************************************************** | |
| 1384 | */ | |
| 1385 | static void arcmsr_dr_handle(struct AdapterControlBlock *acb) { | |
| 1386 | u_int32_t devicemap; | |
| 1387 | u_int32_t target, lun; | |
| 1388 | u_int32_t deviceMapCurrent[4]={0}; | |
| 1389 | u_int8_t *pDevMap; | |
| 1390 | ||
| 1391 | switch (acb->adapter_type) { | |
| 1392 | case ACB_ADAPTER_TYPE_A: | |
| 1393 | devicemap = offsetof(struct HBA_MessageUnit, msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]); | |
| 1394 | for (target= 0; target < 4; target++) | |
| 1395 | { | |
| 1396 | deviceMapCurrent[target]=bus_space_read_4(acb->btag[0], acb->bhandle[0], devicemap); | |
| 1397 | devicemap += 4; | |
| 1398 | } | |
| 1399 | break; | |
| 1400 | ||
| 1401 | case ACB_ADAPTER_TYPE_B: | |
| 1402 | devicemap = offsetof(struct HBB_RWBUFFER, msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]); | |
| 1403 | for (target= 0; target < 4; target++) | |
| 1404 | { | |
| 1405 | deviceMapCurrent[target]=bus_space_read_4(acb->btag[1], acb->bhandle[1], devicemap); | |
| 1406 | devicemap += 4; | |
| 1407 | } | |
| 1408 | break; | |
| 1409 | ||
| 1410 | case ACB_ADAPTER_TYPE_C: | |
| 1411 | devicemap = offsetof(struct HBC_MessageUnit, msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]); | |
| 1412 | for (target= 0; target < 4; target++) | |
| 1413 | { | |
| 1414 | deviceMapCurrent[target]=bus_space_read_4(acb->btag[0], acb->bhandle[0], devicemap); | |
| 1415 | devicemap += 4; | |
| 1416 | } | |
| 1417 | break; | |
| 1418 | } | |
| 1419 | if(acb->acb_flags & ACB_F_BUS_HANG_ON) | |
| 1420 | { | |
| 1421 | acb->acb_flags &= ~ACB_F_BUS_HANG_ON; | |
| 1422 | } | |
| 1423 | /* | |
| 1424 | ** adapter posted CONFIG message | |
| 1425 | ** copy the new map, note if there are differences with the current map | |
| 1426 | */ | |
| 1427 | pDevMap = (u_int8_t *)&deviceMapCurrent[0]; | |
| 1428 | for (target= 0; target < ARCMSR_MAX_TARGETID - 1; target++) | |
| 1429 | { | |
| 1430 | if (*pDevMap != acb->device_map[target]) | |
| 1431 | { | |
| 1432 | u_int8_t difference, bit_check; | |
| 1433 | ||
| 1434 | difference= *pDevMap ^ acb->device_map[target]; | |
| 1435 | for(lun=0; lun < ARCMSR_MAX_TARGETLUN; lun++) | |
| 1436 | { | |
| 1437 | bit_check=(1 << lun); /*check bit from 0....31*/ | |
| 1438 | if(difference & bit_check) | |
| 1439 | { | |
| 1440 | if(acb->device_map[target] & bit_check) | |
| 1441 | {/* unit departed */ | |
| 1442 | kprintf("arcmsr_dr_handle: Target=%x, lun=%x, GONE!!!\n",target,lun); | |
| 1443 | arcmsr_abort_dr_ccbs(acb, target, lun); | |
| 1444 | arcmsr_rescan_lun(acb, target, lun); | |
| 1445 | acb->devstate[target][lun] = ARECA_RAID_GONE; | |
| 1446 | } | |
| 1447 | else | |
| 1448 | {/* unit arrived */ | |
| cc3b439c | 1449 | kprintf("arcmsr_dr_handle: Target=%x, lun=%x, Plug-IN!!!\n",target,lun); |
| 1901a965 SW |
1450 | arcmsr_rescan_lun(acb, target, lun); |
| 1451 | acb->devstate[target][lun] = ARECA_RAID_GOOD; | |
| 1452 | } | |
| 1453 | } | |
| 1454 | } | |
| 1455 | /* kprintf("arcmsr_dr_handle: acb->device_map[%x]=0x%x, deviceMapCurrent[%x]=%x\n",target,acb->device_map[target],target,*pDevMap); */ | |
| 1456 | acb->device_map[target]= *pDevMap; | |
| 1457 | } | |
| 1458 | pDevMap++; | |
| 1459 | } | |
| 1460 | } | |
| 1461 | /* | |
| 1462 | ************************************************************************** | |
| 1463 | ************************************************************************** | |
| 1464 | */ | |
| 1465 | static void arcmsr_hba_message_isr(struct AdapterControlBlock *acb) { | |
| 1466 | u_int32_t outbound_message; | |
| 1467 | ||
| 1468 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intstatus, ARCMSR_MU_OUTBOUND_MESSAGE0_INT); | |
| 1469 | outbound_message = CHIP_REG_READ32(HBA_MessageUnit, 0, msgcode_rwbuffer[0]); | |
| 1470 | if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG) | |
| 1471 | arcmsr_dr_handle( acb ); | |
| 1472 | } | |
| 1473 | /* | |
| 1474 | ************************************************************************** | |
| 1475 | ************************************************************************** | |
| 1476 | */ | |
| 1477 | static void arcmsr_hbb_message_isr(struct AdapterControlBlock *acb) { | |
| 1478 | u_int32_t outbound_message; | |
| 1479 | ||
| 1480 | /* clear interrupts */ | |
| 1481 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, iop2drv_doorbell, ARCMSR_MESSAGE_INT_CLEAR_PATTERN); | |
| 1482 | outbound_message = CHIP_REG_READ32(HBB_RWBUFFER, 1, msgcode_rwbuffer[0]); | |
| 1483 | if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG) | |
| 1484 | arcmsr_dr_handle( acb ); | |
| 1485 | } | |
| 1486 | /* | |
| 1487 | ************************************************************************** | |
| 1488 | ************************************************************************** | |
| 1489 | */ | |
| 1490 | static void arcmsr_hbc_message_isr(struct AdapterControlBlock *acb) { | |
| 1491 | u_int32_t outbound_message; | |
| 1492 | ||
| 1493 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, outbound_doorbell_clear, ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR); | |
| 1494 | outbound_message = CHIP_REG_READ32(HBC_MessageUnit, 0, msgcode_rwbuffer[0]); | |
| 1495 | if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG) | |
| 1496 | arcmsr_dr_handle( acb ); | |
| 1497 | } | |
| 1498 | /* | |
| 1499 | ************************************************************************** | |
| 1500 | ************************************************************************** | |
| 1501 | */ | |
| 1502 | static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb) | |
| 1503 | { | |
| 1504 | u_int32_t outbound_doorbell; | |
| 1505 | ||
| 1506 | /* | |
| 1507 | ******************************************************************* | |
| 1508 | ** Maybe here we need to check wrqbuffer_lock is lock or not | |
| 1509 | ** DOORBELL: din! don! | |
| 1510 | ** check if there are any mail need to pack from firmware | |
| 1511 | ******************************************************************* | |
| 1512 | */ | |
| 1513 | outbound_doorbell=CHIP_REG_READ32(HBA_MessageUnit, | |
| 1514 | 0, outbound_doorbell); | |
| 1515 | CHIP_REG_WRITE32(HBA_MessageUnit, | |
| 1516 | 0, outbound_doorbell, outbound_doorbell); /* clear doorbell interrupt */ | |
| 1517 | if(outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { | |
| 1518 | arcmsr_iop2drv_data_wrote_handle(acb); | |
| 1519 | } | |
| 1520 | if(outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) { | |
| 1521 | arcmsr_iop2drv_data_read_handle(acb); | |
| 1522 | } | |
| 1523 | return; | |
| 1524 | } | |
| 1525 | /* | |
| 1526 | ************************************************************************** | |
| 1527 | ************************************************************************** | |
| 1528 | */ | |
| 1529 | static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *acb) | |
| 1530 | { | |
| 1531 | u_int32_t outbound_doorbell; | |
| 1532 | ||
| 1533 | /* | |
| 1534 | ******************************************************************* | |
| 1535 | ** Maybe here we need to check wrqbuffer_lock is lock or not | |
| 1536 | ** DOORBELL: din! don! | |
| 1537 | ** check if there are any mail need to pack from firmware | |
| 1538 | ******************************************************************* | |
| 1539 | */ | |
| 1540 | outbound_doorbell=CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_doorbell); | |
| 1541 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, outbound_doorbell_clear, outbound_doorbell); /* clear doorbell interrupt */ | |
| 1542 | if(outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) { | |
| 1543 | arcmsr_iop2drv_data_wrote_handle(acb); | |
| 1544 | } | |
| 1545 | if(outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) { | |
| 1546 | arcmsr_iop2drv_data_read_handle(acb); | |
| 1547 | } | |
| 1548 | if(outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { | |
| 1549 | arcmsr_hbc_message_isr(acb); /* messenger of "driver to iop commands" */ | |
| 1550 | } | |
| 1551 | return; | |
| 1552 | } | |
| 1553 | /* | |
| 1554 | ************************************************************************** | |
| 1555 | ************************************************************************** | |
| 1556 | */ | |
| 1557 | static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb) | |
| 1558 | { | |
| 1559 | u_int32_t flag_srb; | |
| 1560 | u_int16_t error; | |
| 1561 | ||
| 1562 | /* | |
| 1563 | ***************************************************************************** | |
| 1564 | ** areca cdb command done | |
| 1565 | ***************************************************************************** | |
| 1566 | */ | |
| 1567 | bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, | |
| 1568 | BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); | |
| 1569 | while((flag_srb=CHIP_REG_READ32(HBA_MessageUnit, | |
| 1570 | 0, outbound_queueport)) != 0xFFFFFFFF) { | |
| 1571 | /* check if command done with no error*/ | |
| 1572 | error=(flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE0)?TRUE:FALSE; | |
| 1573 | arcmsr_drain_donequeue(acb, flag_srb, error); | |
| 1574 | } /*drain reply FIFO*/ | |
| 1575 | return; | |
| 1576 | } | |
| 1577 | /* | |
| 1578 | ************************************************************************** | |
| 1579 | ************************************************************************** | |
| 1580 | */ | |
| 1581 | static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb) | |
| 1582 | { | |
| 1583 | struct HBB_MessageUnit *phbbmu=(struct HBB_MessageUnit *)acb->pmu; | |
| 1584 | u_int32_t flag_srb; | |
| 1585 | int index; | |
| 1586 | u_int16_t error; | |
| 1587 | ||
| 1588 | /* | |
| 1589 | ***************************************************************************** | |
| 1590 | ** areca cdb command done | |
| 1591 | ***************************************************************************** | |
| 1592 | */ | |
| 1593 | bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, | |
| 1594 | BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); | |
| 1595 | index=phbbmu->doneq_index; | |
| 1596 | while((flag_srb=phbbmu->done_qbuffer[index]) != 0) { | |
| 1597 | phbbmu->done_qbuffer[index]=0; | |
| 1598 | index++; | |
| 1599 | index %= ARCMSR_MAX_HBB_POSTQUEUE; /*if last index number set it to 0 */ | |
| 1600 | phbbmu->doneq_index=index; | |
| 1601 | /* check if command done with no error*/ | |
| 1602 | error=(flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE0)?TRUE:FALSE; | |
| 1603 | arcmsr_drain_donequeue(acb, flag_srb, error); | |
| 1604 | } /*drain reply FIFO*/ | |
| 1605 | return; | |
| 1606 | } | |
| 1607 | /* | |
| 1608 | ************************************************************************** | |
| 1609 | ************************************************************************** | |
| 1610 | */ | |
| 1611 | static void arcmsr_hbc_postqueue_isr(struct AdapterControlBlock *acb) | |
| 1612 | { | |
| 1613 | u_int32_t flag_srb,throttling=0; | |
| 1614 | u_int16_t error; | |
| 1615 | ||
| 1616 | /* | |
| 1617 | ***************************************************************************** | |
| 1618 | ** areca cdb command done | |
| 1619 | ***************************************************************************** | |
| 1620 | */ | |
| 1621 | bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); | |
| 1622 | ||
| 1623 | while(CHIP_REG_READ32(HBC_MessageUnit, 0, host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) { | |
| 1624 | ||
| 1625 | flag_srb=CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_queueport_low); | |
| 1626 | /* check if command done with no error*/ | |
| 1627 | error=(flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE1)?TRUE:FALSE; | |
| 1628 | arcmsr_drain_donequeue(acb, flag_srb, error); | |
| 1629 | if(throttling==ARCMSR_HBC_ISR_THROTTLING_LEVEL) { | |
| 1630 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell,ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING); | |
| 1631 | break; | |
| 1632 | } | |
| 1633 | throttling++; | |
| 1634 | } /*drain reply FIFO*/ | |
| 1635 | return; | |
| 1636 | } | |
| 1637 | /* | |
| 1638 | ********************************************************************** | |
| 1639 | ********************************************************************** | |
| 1640 | */ | |
| 1641 | static void arcmsr_handle_hba_isr( struct AdapterControlBlock *acb) | |
| 1642 | { | |
| 1643 | u_int32_t outbound_intstatus; | |
| 1644 | /* | |
| 1645 | ********************************************* | |
| 1646 | ** check outbound intstatus | |
| 1647 | ********************************************* | |
| 1648 | */ | |
| 1649 | outbound_intstatus=CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_intstatus) & acb->outbound_int_enable; | |
| 1650 | if(!outbound_intstatus) { | |
| 1651 | /*it must be share irq*/ | |
| 1652 | return; | |
| 1653 | } | |
| 1654 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intstatus, outbound_intstatus);/*clear interrupt*/ | |
| 1655 | /* MU doorbell interrupts*/ | |
| 1656 | if(outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) { | |
| 1657 | arcmsr_hba_doorbell_isr(acb); | |
| 1658 | } | |
| 1659 | /* MU post queue interrupts*/ | |
| 1660 | if(outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) { | |
| 1661 | arcmsr_hba_postqueue_isr(acb); | |
| 1662 | } | |
| 1663 | if(outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { | |
| 1664 | arcmsr_hba_message_isr(acb); | |
| 1665 | } | |
| 1666 | return; | |
| 1667 | } | |
| 1668 | /* | |
| 1669 | ********************************************************************** | |
| 1670 | ********************************************************************** | |
| 1671 | */ | |
| 1672 | static void arcmsr_handle_hbb_isr( struct AdapterControlBlock *acb) | |
| 1673 | { | |
| 1674 | u_int32_t outbound_doorbell; | |
| 1675 | /* | |
| 1676 | ********************************************* | |
| 1677 | ** check outbound intstatus | |
| 1678 | ********************************************* | |
| 1679 | */ | |
| 1680 | outbound_doorbell=CHIP_REG_READ32(HBB_DOORBELL, 0, iop2drv_doorbell) & acb->outbound_int_enable; | |
| 1681 | if(!outbound_doorbell) { | |
| 1682 | /*it must be share irq*/ | |
| 1683 | return; | |
| 1684 | } | |
| 1685 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, iop2drv_doorbell, ~outbound_doorbell); /* clear doorbell interrupt */ | |
| 1686 | CHIP_REG_READ32(HBB_DOORBELL, 0, iop2drv_doorbell); | |
| 1687 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_DRV2IOP_END_OF_INTERRUPT); | |
| 1688 | /* MU ioctl transfer doorbell interrupts*/ | |
| 1689 | if(outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) { | |
| 1690 | arcmsr_iop2drv_data_wrote_handle(acb); | |
| 1691 | } | |
| 1692 | if(outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) { | |
| 1693 | arcmsr_iop2drv_data_read_handle(acb); | |
| 1694 | } | |
| 1695 | /* MU post queue interrupts*/ | |
| 1696 | if(outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) { | |
| 1697 | arcmsr_hbb_postqueue_isr(acb); | |
| 1698 | } | |
| 1699 | if(outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { | |
| 1700 | arcmsr_hbb_message_isr(acb); | |
| 1701 | } | |
| 1702 | return; | |
| 1703 | } | |
| 1704 | /* | |
| 1705 | ********************************************************************** | |
| 1706 | ********************************************************************** | |
| 1707 | */ | |
| 1708 | static void arcmsr_handle_hbc_isr( struct AdapterControlBlock *acb) | |
| 1709 | { | |
| 1710 | u_int32_t host_interrupt_status; | |
| 1711 | /* | |
| 1712 | ********************************************* | |
| 1713 | ** check outbound intstatus | |
| 1714 | ********************************************* | |
| 1715 | */ | |
| 1716 | host_interrupt_status=CHIP_REG_READ32(HBC_MessageUnit, 0, host_int_status); | |
| 1717 | if(!host_interrupt_status) { | |
| 1718 | /*it must be share irq*/ | |
| 1719 | return; | |
| 1720 | } | |
| 1721 | /* MU doorbell interrupts*/ | |
| 1722 | if(host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR) { | |
| 1723 | arcmsr_hbc_doorbell_isr(acb); | |
| 1724 | } | |
| 1725 | /* MU post queue interrupts*/ | |
| 1726 | if(host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) { | |
| 1727 | arcmsr_hbc_postqueue_isr(acb); | |
| 1728 | } | |
| 1729 | return; | |
| 1730 | } | |
| 1731 | /* | |
| 1732 | ****************************************************************************** | |
| 1733 | ****************************************************************************** | |
| 1734 | */ | |
| 1735 | static void arcmsr_interrupt(struct AdapterControlBlock *acb) | |
| 1736 | { | |
| 1737 | switch (acb->adapter_type) { | |
| 1738 | case ACB_ADAPTER_TYPE_A: | |
| 1739 | arcmsr_handle_hba_isr(acb); | |
| 1740 | break; | |
| 1741 | case ACB_ADAPTER_TYPE_B: | |
| 1742 | arcmsr_handle_hbb_isr(acb); | |
| 1743 | break; | |
| 1744 | case ACB_ADAPTER_TYPE_C: | |
| 1745 | arcmsr_handle_hbc_isr(acb); | |
| 1746 | break; | |
| 1747 | default: | |
| 1748 | kprintf("arcmsr%d: interrupt service," | |
| 1749 | " unknow adapter type =%d\n", acb->pci_unit, acb->adapter_type); | |
| 1750 | break; | |
| 1751 | } | |
| 1752 | return; | |
| 1753 | } | |
| 1754 | /* | |
| 1755 | ********************************************************************** | |
| 1756 | ********************************************************************** | |
| 1757 | */ | |
| 1758 | static void arcmsr_intr_handler(void *arg) | |
| 1759 | { | |
| 1760 | struct AdapterControlBlock *acb=(struct AdapterControlBlock *)arg; | |
| 1761 | ||
| 1762 | ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); | |
| 1763 | arcmsr_interrupt(acb); | |
| 1764 | ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); | |
| 1765 | } | |
| 1766 | /* | |
| 1767 | ****************************************************************************** | |
| 1768 | ****************************************************************************** | |
| 1769 | */ | |
| 1770 | static void arcmsr_polling_devmap(void* arg) | |
| 1771 | { | |
| 1772 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *)arg; | |
| 1773 | switch (acb->adapter_type) { | |
| 1774 | case ACB_ADAPTER_TYPE_A: | |
| 1775 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG); | |
| 1776 | break; | |
| 1777 | ||
| 1778 | case ACB_ADAPTER_TYPE_B: | |
| 1779 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_MESSAGE_GET_CONFIG); | |
| 1780 | break; | |
| 1781 | ||
| 1782 | case ACB_ADAPTER_TYPE_C: | |
| 1783 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG); | |
| 1784 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE); | |
| 1785 | break; | |
| 1786 | } | |
| 1787 | ||
| 1788 | if((acb->acb_flags & ACB_F_SCSISTOPADAPTER) == 0) | |
| 1789 | { | |
| 1790 | callout_reset(&acb->devmap_callout, 5 * hz, arcmsr_polling_devmap, acb); /* polling per 5 seconds */ | |
| 1791 | } | |
| 1792 | } | |
| 1793 | ||
| 1794 | /* | |
| 1795 | ******************************************************************************* | |
| 1796 | ** | |
| 1797 | ******************************************************************************* | |
| 1798 | */ | |
| 1799 | static void arcmsr_iop_parking(struct AdapterControlBlock *acb) | |
| 1800 | { | |
| 1801 | u_int32_t intmask_org; | |
| 1802 | ||
| 1803 | if(acb!=NULL) { | |
| 1804 | /* stop adapter background rebuild */ | |
| 1805 | if(acb->acb_flags & ACB_F_MSG_START_BGRB) { | |
| 1806 | intmask_org = arcmsr_disable_allintr(acb); | |
| 1807 | arcmsr_stop_adapter_bgrb(acb); | |
| 1808 | arcmsr_flush_adapter_cache(acb); | |
| 1809 | arcmsr_enable_allintr(acb, intmask_org); | |
| 1810 | } | |
| 1811 | } | |
| 1812 | } | |
| 1813 | /* | |
| 1814 | *********************************************************************** | |
| 1815 | ** | |
| 1816 | ************************************************************************ | |
| 1817 | */ | |
| 1818 | u_int32_t arcmsr_iop_ioctlcmd(struct AdapterControlBlock *acb, u_int32_t ioctl_cmd, caddr_t arg) | |
| 1819 | { | |
| 1820 | struct CMD_MESSAGE_FIELD * pcmdmessagefld; | |
| 1821 | u_int32_t retvalue=EINVAL; | |
| 1822 | ||
| 1823 | pcmdmessagefld=(struct CMD_MESSAGE_FIELD *) arg; | |
| 1824 | if(memcmp(pcmdmessagefld->cmdmessage.Signature, "ARCMSR", 6)!=0) { | |
| 1825 | return retvalue; | |
| 1826 | } | |
| 1827 | ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); | |
| 1828 | switch(ioctl_cmd) { | |
| 1829 | case ARCMSR_MESSAGE_READ_RQBUFFER: { | |
| 1830 | u_int8_t * pQbuffer; | |
| 1831 | u_int8_t * ptmpQbuffer=pcmdmessagefld->messagedatabuffer; | |
| 1832 | u_int32_t allxfer_len=0; | |
| 1833 | ||
| 1834 | while((acb->rqbuf_firstindex!=acb->rqbuf_lastindex) | |
| 1835 | && (allxfer_len<1031)) { | |
| 1836 | /*copy READ QBUFFER to srb*/ | |
| 1837 | pQbuffer= &acb->rqbuffer[acb->rqbuf_firstindex]; | |
| 1838 | memcpy(ptmpQbuffer, pQbuffer, 1); | |
| 1839 | acb->rqbuf_firstindex++; | |
| 1840 | acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; | |
| 1841 | /*if last index number set it to 0 */ | |
| 1842 | ptmpQbuffer++; | |
| 1843 | allxfer_len++; | |
| 1844 | } | |
| 1845 | if(acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | |
| 1846 | struct QBUFFER * prbuffer; | |
| 1847 | u_int8_t * iop_data; | |
| 1848 | u_int32_t iop_len; | |
| 1849 | ||
| 1850 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | |
| 1851 | prbuffer=arcmsr_get_iop_rqbuffer(acb); | |
| 1852 | iop_data=(u_int8_t *)prbuffer->data; | |
| 1853 | iop_len=(u_int32_t)prbuffer->data_len; | |
| 1854 | /*this iop data does no chance to make me overflow again here, so just do it*/ | |
| 1855 | while(iop_len>0) { | |
| 1856 | pQbuffer= &acb->rqbuffer[acb->rqbuf_lastindex]; | |
| 1857 | memcpy(pQbuffer, iop_data, 1); | |
| 1858 | acb->rqbuf_lastindex++; | |
| 1859 | acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; | |
| 1860 | /*if last index number set it to 0 */ | |
| 1861 | iop_data++; | |
| 1862 | iop_len--; | |
| 1863 | } | |
| 1864 | arcmsr_iop_message_read(acb); | |
| 1865 | /*signature, let IOP know data has been readed */ | |
| 1866 | } | |
| 1867 | pcmdmessagefld->cmdmessage.Length=allxfer_len; | |
| 1868 | pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_OK; | |
| 1869 | retvalue=ARCMSR_MESSAGE_SUCCESS; | |
| 1870 | } | |
| 1871 | break; | |
| 1872 | case ARCMSR_MESSAGE_WRITE_WQBUFFER: { | |
| 1873 | u_int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; | |
| 1874 | u_int8_t * pQbuffer; | |
| 1875 | u_int8_t * ptmpuserbuffer=pcmdmessagefld->messagedatabuffer; | |
| 1876 | ||
| 1877 | user_len=pcmdmessagefld->cmdmessage.Length; | |
| 1878 | /*check if data xfer length of this request will overflow my array qbuffer */ | |
| 1879 | wqbuf_lastindex=acb->wqbuf_lastindex; | |
| 1880 | wqbuf_firstindex=acb->wqbuf_firstindex; | |
| 1881 | if(wqbuf_lastindex!=wqbuf_firstindex) { | |
| 1882 | arcmsr_post_ioctldata2iop(acb); | |
| 1883 | pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_ERROR; | |
| 1884 | } else { | |
| 1885 | my_empty_len=(wqbuf_firstindex-wqbuf_lastindex-1)&(ARCMSR_MAX_QBUFFER-1); | |
| 1886 | if(my_empty_len>=user_len) { | |
| 1887 | while(user_len>0) { | |
| 1888 | /*copy srb data to wqbuffer*/ | |
| 1889 | pQbuffer= &acb->wqbuffer[acb->wqbuf_lastindex]; | |
| 1890 | memcpy(pQbuffer, ptmpuserbuffer, 1); | |
| 1891 | acb->wqbuf_lastindex++; | |
| 1892 | acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; | |
| 1893 | /*if last index number set it to 0 */ | |
| 1894 | ptmpuserbuffer++; | |
| 1895 | user_len--; | |
| 1896 | } | |
| 1897 | /*post fist Qbuffer*/ | |
| 1898 | if(acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { | |
| 1899 | acb->acb_flags &=~ACB_F_MESSAGE_WQBUFFER_CLEARED; | |
| 1900 | arcmsr_post_ioctldata2iop(acb); | |
| 1901 | } | |
| 1902 | pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_OK; | |
| 1903 | } else { | |
| 1904 | pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_ERROR; | |
| 1905 | } | |
| 1906 | } | |
| 1907 | retvalue=ARCMSR_MESSAGE_SUCCESS; | |
| 1908 | } | |
| 1909 | break; | |
| 1910 | case ARCMSR_MESSAGE_CLEAR_RQBUFFER: { | |
| 1911 | u_int8_t * pQbuffer=acb->rqbuffer; | |
| 1912 | ||
| 1913 | if(acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | |
| 1914 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | |
| 1915 | arcmsr_iop_message_read(acb); | |
| 1916 | /*signature, let IOP know data has been readed */ | |
| 1917 | } | |
| 1918 | acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; | |
| 1919 | acb->rqbuf_firstindex=0; | |
| 1920 | acb->rqbuf_lastindex=0; | |
| 1921 | memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); | |
| 1922 | pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_OK; | |
| 1923 | retvalue=ARCMSR_MESSAGE_SUCCESS; | |
| 1924 | } | |
| 1925 | break; | |
| 1926 | case ARCMSR_MESSAGE_CLEAR_WQBUFFER: | |
| 1927 | { | |
| 1928 | u_int8_t * pQbuffer=acb->wqbuffer; | |
| 1929 | ||
| 1930 | if(acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | |
| 1931 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | |
| 1932 | arcmsr_iop_message_read(acb); | |
| 1933 | /*signature, let IOP know data has been readed */ | |
| 1934 | } | |
| 1935 | acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED|ACB_F_MESSAGE_WQBUFFER_READ); | |
| 1936 | acb->wqbuf_firstindex=0; | |
| 1937 | acb->wqbuf_lastindex=0; | |
| 1938 | memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); | |
| 1939 | pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_OK; | |
| 1940 | retvalue=ARCMSR_MESSAGE_SUCCESS; | |
| 1941 | } | |
| 1942 | break; | |
| 1943 | case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: { | |
| 1944 | u_int8_t * pQbuffer; | |
| 1945 | ||
| 1946 | if(acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | |
| 1947 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | |
| 1948 | arcmsr_iop_message_read(acb); | |
| 1949 | /*signature, let IOP know data has been readed */ | |
| 1950 | } | |
| 1951 | acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | |
| 1952 | |ACB_F_MESSAGE_RQBUFFER_CLEARED | |
| 1953 | |ACB_F_MESSAGE_WQBUFFER_READ); | |
| 1954 | acb->rqbuf_firstindex=0; | |
| 1955 | acb->rqbuf_lastindex=0; | |
| 1956 | acb->wqbuf_firstindex=0; | |
| 1957 | acb->wqbuf_lastindex=0; | |
| 1958 | pQbuffer=acb->rqbuffer; | |
| 1959 | memset(pQbuffer, 0, sizeof(struct QBUFFER)); | |
| 1960 | pQbuffer=acb->wqbuffer; | |
| 1961 | memset(pQbuffer, 0, sizeof(struct QBUFFER)); | |
| 1962 | pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_OK; | |
| 1963 | retvalue=ARCMSR_MESSAGE_SUCCESS; | |
| 1964 | } | |
| 1965 | break; | |
| 1966 | case ARCMSR_MESSAGE_REQUEST_RETURNCODE_3F: { | |
| 1967 | pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_3F; | |
| 1968 | retvalue=ARCMSR_MESSAGE_SUCCESS; | |
| 1969 | } | |
| 1970 | break; | |
| 1971 | case ARCMSR_MESSAGE_SAY_HELLO: { | |
| 1972 | u_int8_t * hello_string="Hello! I am ARCMSR"; | |
| 1973 | u_int8_t * puserbuffer=(u_int8_t *)pcmdmessagefld->messagedatabuffer; | |
| 1974 | ||
| 1975 | if(memcpy(puserbuffer, hello_string, (int16_t)strlen(hello_string))) { | |
| 1976 | pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_ERROR; | |
| 1977 | ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); | |
| 1978 | return ENOIOCTL; | |
| 1979 | } | |
| 1980 | pcmdmessagefld->cmdmessage.ReturnCode=ARCMSR_MESSAGE_RETURNCODE_OK; | |
| 1981 | retvalue=ARCMSR_MESSAGE_SUCCESS; | |
| 1982 | } | |
| 1983 | break; | |
| 1984 | case ARCMSR_MESSAGE_SAY_GOODBYE: { | |
| 1985 | arcmsr_iop_parking(acb); | |
| 1986 | retvalue=ARCMSR_MESSAGE_SUCCESS; | |
| 1987 | } | |
| 1988 | break; | |
| 1989 | case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: { | |
| 1990 | arcmsr_flush_adapter_cache(acb); | |
| 1991 | retvalue=ARCMSR_MESSAGE_SUCCESS; | |
| 1992 | } | |
| 1993 | break; | |
| 1994 | } | |
| 1995 | ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); | |
| 1996 | return retvalue; | |
| 1997 | } | |
| 1998 | /* | |
| 1999 | ************************************************************************** | |
| 2000 | ************************************************************************** | |
| 2001 | */ | |
| cc3b439c SW |
2002 | static void arcmsr_free_srb(struct CommandControlBlock *srb) |
| 2003 | { | |
| 2004 | struct AdapterControlBlock *acb; | |
| 2005 | int mutex; | |
| 2006 | ||
| 2007 | acb = srb->acb; | |
| 2008 | mutex = lockstatus(&acb->qbuffer_lock, curthread); | |
| 2009 | if( mutex == 0 ) | |
| 2010 | ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); | |
| 2011 | srb->srb_state=ARCMSR_SRB_DONE; | |
| 2012 | srb->srb_flags=0; | |
| 2013 | acb->srbworkingQ[acb->workingsrb_doneindex]=srb; | |
| 2014 | acb->workingsrb_doneindex++; | |
| 2015 | acb->workingsrb_doneindex %= ARCMSR_MAX_FREESRB_NUM; | |
| 2016 | if( mutex == 0 ) | |
| 2017 | ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); | |
| 2018 | } | |
| 2019 | /* | |
| 2020 | ************************************************************************** | |
| 2021 | ************************************************************************** | |
| 2022 | */ | |
| 1901a965 SW |
2023 | struct CommandControlBlock * arcmsr_get_freesrb(struct AdapterControlBlock *acb) |
| 2024 | { | |
| 2025 | struct CommandControlBlock *srb=NULL; | |
| 2026 | u_int32_t workingsrb_startindex, workingsrb_doneindex; | |
| cc3b439c | 2027 | int mutex; |
| 1901a965 | 2028 | |
| cc3b439c SW |
2029 | mutex = lockstatus(&acb->qbuffer_lock, curthread); |
| 2030 | if( mutex == 0 ) | |
| 2031 | ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); | |
| 1901a965 SW |
2032 | workingsrb_doneindex=acb->workingsrb_doneindex; |
| 2033 | workingsrb_startindex=acb->workingsrb_startindex; | |
| 2034 | srb=acb->srbworkingQ[workingsrb_startindex]; | |
| 2035 | workingsrb_startindex++; | |
| 2036 | workingsrb_startindex %= ARCMSR_MAX_FREESRB_NUM; | |
| 2037 | if(workingsrb_doneindex!=workingsrb_startindex) { | |
| 2038 | acb->workingsrb_startindex=workingsrb_startindex; | |
| 2039 | } else { | |
| 2040 | srb=NULL; | |
| 2041 | } | |
| cc3b439c SW |
2042 | if( mutex == 0 ) |
| 2043 | ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); | |
| 1901a965 SW |
2044 | return(srb); |
| 2045 | } | |
| 2046 | /* | |
| 2047 | ************************************************************************** | |
| 2048 | ************************************************************************** | |
| 2049 | */ | |
| 2050 | static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, union ccb * pccb) | |
| 2051 | { | |
| 2052 | struct CMD_MESSAGE_FIELD * pcmdmessagefld; | |
| 2053 | int retvalue = 0, transfer_len = 0; | |
| 2054 | char *buffer; | |
| 2055 | u_int32_t controlcode = (u_int32_t ) pccb->csio.cdb_io.cdb_bytes[5] << 24 | | |
| 2056 | (u_int32_t ) pccb->csio.cdb_io.cdb_bytes[6] << 16 | | |
| 2057 | (u_int32_t ) pccb->csio.cdb_io.cdb_bytes[7] << 8 | | |
| 2058 | (u_int32_t ) pccb->csio.cdb_io.cdb_bytes[8]; | |
| 2059 | /* 4 bytes: Areca io control code */ | |
| 2060 | if((pccb->ccb_h.flags & CAM_SCATTER_VALID) == 0) { | |
| 2061 | buffer = pccb->csio.data_ptr; | |
| 2062 | transfer_len = pccb->csio.dxfer_len; | |
| 2063 | } else { | |
| 2064 | retvalue = ARCMSR_MESSAGE_FAIL; | |
| 2065 | goto message_out; | |
| 2066 | } | |
| 2067 | if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) { | |
| 2068 | retvalue = ARCMSR_MESSAGE_FAIL; | |
| 2069 | goto message_out; | |
| 2070 | } | |
| 2071 | pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer; | |
| 2072 | switch(controlcode) { | |
| 2073 | case ARCMSR_MESSAGE_READ_RQBUFFER: { | |
| 2074 | u_int8_t *pQbuffer; | |
| 2075 | u_int8_t *ptmpQbuffer=pcmdmessagefld->messagedatabuffer; | |
| 2076 | int32_t allxfer_len = 0; | |
| 2077 | ||
| 2078 | while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) | |
| 2079 | && (allxfer_len < 1031)) { | |
| 2080 | pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; | |
| 2081 | memcpy(ptmpQbuffer, pQbuffer, 1); | |
| 2082 | acb->rqbuf_firstindex++; | |
| 2083 | acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; | |
| 2084 | ptmpQbuffer++; | |
| 2085 | allxfer_len++; | |
| 2086 | } | |
| 2087 | if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | |
| 2088 | struct QBUFFER *prbuffer; | |
| 2089 | u_int8_t *iop_data; | |
| 2090 | int32_t iop_len; | |
| 2091 | ||
| 2092 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | |
| 2093 | prbuffer=arcmsr_get_iop_rqbuffer(acb); | |
| 2094 | iop_data = (u_int8_t *)prbuffer->data; | |
| 2095 | iop_len =(u_int32_t)prbuffer->data_len; | |
| 2096 | while (iop_len > 0) { | |
| 2097 | pQbuffer= &acb->rqbuffer[acb->rqbuf_lastindex]; | |
| 2098 | memcpy(pQbuffer, iop_data, 1); | |
| 2099 | acb->rqbuf_lastindex++; | |
| 2100 | acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; | |
| 2101 | iop_data++; | |
| 2102 | iop_len--; | |
| 2103 | } | |
| 2104 | arcmsr_iop_message_read(acb); | |
| 2105 | } | |
| 2106 | pcmdmessagefld->cmdmessage.Length = allxfer_len; | |
| 2107 | pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; | |
| 2108 | retvalue=ARCMSR_MESSAGE_SUCCESS; | |
| 2109 | } | |
| 2110 | break; | |
| 2111 | case ARCMSR_MESSAGE_WRITE_WQBUFFER: { | |
| 2112 | int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; | |
| 2113 | u_int8_t *pQbuffer; | |
| 2114 | u_int8_t *ptmpuserbuffer=pcmdmessagefld->messagedatabuffer; | |
| 2115 | ||
| 2116 | user_len = pcmdmessagefld->cmdmessage.Length; | |
| 2117 | wqbuf_lastindex = acb->wqbuf_lastindex; | |
| 2118 | wqbuf_firstindex = acb->wqbuf_firstindex; | |
| 2119 | if (wqbuf_lastindex != wqbuf_firstindex) { | |
| 2120 | arcmsr_post_ioctldata2iop(acb); | |
| 2121 | /* has error report sensedata */ | |
| 6d4343ee | 2122 | if(pccb->csio.sense_len) { |
| 1901a965 SW |
2123 | ((u_int8_t *)&pccb->csio.sense_data)[0] = (0x1 << 7 | 0x70); |
| 2124 | /* Valid,ErrorCode */ | |
| 2125 | ((u_int8_t *)&pccb->csio.sense_data)[2] = 0x05; | |
| 2126 | /* FileMark,EndOfMedia,IncorrectLength,Reserved,SenseKey */ | |
| 2127 | ((u_int8_t *)&pccb->csio.sense_data)[7] = 0x0A; | |
| 2128 | /* AdditionalSenseLength */ | |
| 2129 | ((u_int8_t *)&pccb->csio.sense_data)[12] = 0x20; | |
| 2130 | /* AdditionalSenseCode */ | |
| 2131 | } | |
| 2132 | retvalue = ARCMSR_MESSAGE_FAIL; | |
| 2133 | } else { | |
| 2134 | my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) | |
| 2135 | &(ARCMSR_MAX_QBUFFER - 1); | |
| 2136 | if (my_empty_len >= user_len) { | |
| 2137 | while (user_len > 0) { | |
| 2138 | pQbuffer = &acb->wqbuffer[acb->wqbuf_lastindex]; | |
| 2139 | memcpy(pQbuffer, ptmpuserbuffer, 1); | |
| 2140 | acb->wqbuf_lastindex++; | |
| 2141 | acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; | |
| 2142 | ptmpuserbuffer++; | |
| 2143 | user_len--; | |
| 2144 | } | |
| 2145 | if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { | |
| 2146 | acb->acb_flags &= | |
| 2147 | ~ACB_F_MESSAGE_WQBUFFER_CLEARED; | |
| 2148 | arcmsr_post_ioctldata2iop(acb); | |
| 2149 | } | |
| 2150 | } else { | |
| 2151 | /* has error report sensedata */ | |
| 6d4343ee | 2152 | if(pccb->csio.sense_len) { |
| 1901a965 SW |
2153 | ((u_int8_t *)&pccb->csio.sense_data)[0] = (0x1 << 7 | 0x70); |
| 2154 | /* Valid,ErrorCode */ | |
| 2155 | ((u_int8_t *)&pccb->csio.sense_data)[2] = 0x05; | |
| 2156 | /* FileMark,EndOfMedia,IncorrectLength,Reserved,SenseKey */ | |
| 2157 | ((u_int8_t *)&pccb->csio.sense_data)[7] = 0x0A; | |
| 2158 | /* AdditionalSenseLength */ | |
| 2159 | ((u_int8_t *)&pccb->csio.sense_data)[12] = 0x20; | |
| 2160 | /* AdditionalSenseCode */ | |
| 2161 | } | |
| 2162 | retvalue = ARCMSR_MESSAGE_FAIL; | |
| 2163 | } | |
| 2164 | } | |
| 2165 | } | |
| 2166 | break; | |
| 2167 | case ARCMSR_MESSAGE_CLEAR_RQBUFFER: { | |
| 2168 | u_int8_t *pQbuffer = acb->rqbuffer; | |
| 2169 | ||
| 2170 | if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | |
| 2171 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | |
| 2172 | arcmsr_iop_message_read(acb); | |
| 2173 | } | |
| 2174 | acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; | |
| 2175 | acb->rqbuf_firstindex = 0; | |
| 2176 | acb->rqbuf_lastindex = 0; | |
| 2177 | memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); | |
| 2178 | pcmdmessagefld->cmdmessage.ReturnCode = | |
| 2179 | ARCMSR_MESSAGE_RETURNCODE_OK; | |
| 2180 | } | |
| 2181 | break; | |
| 2182 | case ARCMSR_MESSAGE_CLEAR_WQBUFFER: { | |
| 2183 | u_int8_t *pQbuffer = acb->wqbuffer; | |
| 2184 | ||
| 2185 | if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | |
| 2186 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | |
| 2187 | arcmsr_iop_message_read(acb); | |
| 2188 | } | |
| 2189 | acb->acb_flags |= | |
| 2190 | (ACB_F_MESSAGE_WQBUFFER_CLEARED | | |
| 2191 | ACB_F_MESSAGE_WQBUFFER_READ); | |
| 2192 | acb->wqbuf_firstindex = 0; | |
| 2193 | acb->wqbuf_lastindex = 0; | |
| 2194 | memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); | |
| 2195 | pcmdmessagefld->cmdmessage.ReturnCode = | |
| 2196 | ARCMSR_MESSAGE_RETURNCODE_OK; | |
| 2197 | } | |
| 2198 | break; | |
| 2199 | case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: { | |
| 2200 | u_int8_t *pQbuffer; | |
| 2201 | ||
| 2202 | if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | |
| 2203 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | |
| 2204 | arcmsr_iop_message_read(acb); | |
| 2205 | } | |
| 2206 | acb->acb_flags |= | |
| 2207 | (ACB_F_MESSAGE_WQBUFFER_CLEARED | |
| 2208 | | ACB_F_MESSAGE_RQBUFFER_CLEARED | |
| 2209 | | ACB_F_MESSAGE_WQBUFFER_READ); | |
| 2210 | acb->rqbuf_firstindex = 0; | |
| 2211 | acb->rqbuf_lastindex = 0; | |
| 2212 | acb->wqbuf_firstindex = 0; | |
| 2213 | acb->wqbuf_lastindex = 0; | |
| 2214 | pQbuffer = acb->rqbuffer; | |
| 2215 | memset(pQbuffer, 0, sizeof (struct QBUFFER)); | |
| 2216 | pQbuffer = acb->wqbuffer; | |
| 2217 | memset(pQbuffer, 0, sizeof (struct QBUFFER)); | |
| 2218 | pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; | |
| 2219 | } | |
| 2220 | break; | |
| 2221 | case ARCMSR_MESSAGE_REQUEST_RETURNCODE_3F: { | |
| 2222 | pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F; | |
| 2223 | } | |
| 2224 | break; | |
| 2225 | case ARCMSR_MESSAGE_SAY_HELLO: { | |
| 2226 | int8_t * hello_string = "Hello! I am ARCMSR"; | |
| 2227 | ||
| 2228 | memcpy(pcmdmessagefld->messagedatabuffer, hello_string | |
| 2229 | , (int16_t)strlen(hello_string)); | |
| 2230 | pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; | |
| 2231 | } | |
| 2232 | break; | |
| 2233 | case ARCMSR_MESSAGE_SAY_GOODBYE: | |
| 2234 | arcmsr_iop_parking(acb); | |
| 2235 | break; | |
| 2236 | case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: | |
| 2237 | arcmsr_flush_adapter_cache(acb); | |
| 2238 | break; | |
| 2239 | default: | |
| 2240 | retvalue = ARCMSR_MESSAGE_FAIL; | |
| 2241 | } | |
| 2242 | message_out: | |
| 2243 | return retvalue; | |
| 2244 | } | |
| 2245 | /* | |
| 2246 | ********************************************************************* | |
| 2247 | ********************************************************************* | |
| 2248 | */ | |
| 95696aa4 | 2249 | static void arcmsr_execute_srb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) |
| 1901a965 SW |
2250 | { |
| 2251 | struct CommandControlBlock *srb=(struct CommandControlBlock *)arg; | |
| 2252 | struct AdapterControlBlock *acb=(struct AdapterControlBlock *)srb->acb; | |
| 2253 | union ccb * pccb; | |
| 2254 | int target, lun; | |
| 2255 | ||
| 2256 | pccb=srb->pccb; | |
| 2257 | target=pccb->ccb_h.target_id; | |
| 2258 | lun=pccb->ccb_h.target_lun; | |
| cc3b439c SW |
2259 | #ifdef ARCMSR_DEBUG1 |
| 2260 | acb->pktRequestCount++; | |
| 2261 | #endif | |
| 1901a965 SW |
2262 | if(error != 0) { |
| 2263 | if(error != EFBIG) { | |
| 2264 | kprintf("arcmsr%d: unexpected error %x" | |
| 2265 | " returned from 'bus_dmamap_load' \n" | |
| 2266 | , acb->pci_unit, error); | |
| 2267 | } | |
| 2268 | if((pccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { | |
| 2269 | pccb->ccb_h.status |= CAM_REQ_TOO_BIG; | |
| 2270 | } | |
| 2271 | arcmsr_srb_complete(srb, 0); | |
| 2272 | return; | |
| 2273 | } | |
| 2274 | if(nseg > ARCMSR_MAX_SG_ENTRIES) { | |
| 2275 | pccb->ccb_h.status |= CAM_REQ_TOO_BIG; | |
| 2276 | arcmsr_srb_complete(srb, 0); | |
| 2277 | return; | |
| 2278 | } | |
| 2279 | if(acb->acb_flags & ACB_F_BUS_RESET) { | |
| 2280 | kprintf("arcmsr%d: bus reset and return busy \n", acb->pci_unit); | |
| 2281 | pccb->ccb_h.status |= CAM_SCSI_BUS_RESET; | |
| 2282 | arcmsr_srb_complete(srb, 0); | |
| 2283 | return; | |
| 2284 | } | |
| 2285 | if(acb->devstate[target][lun]==ARECA_RAID_GONE) { | |
| cc3b439c | 2286 | u_int8_t block_cmd, cmd; |
| 1901a965 | 2287 | |
| cc3b439c SW |
2288 | cmd = pccb->csio.cdb_io.cdb_bytes[0]; |
| 2289 | block_cmd= cmd & 0x0f; | |
| 1901a965 SW |
2290 | if(block_cmd==0x08 || block_cmd==0x0a) { |
| 2291 | kprintf("arcmsr%d:block 'read/write' command " | |
| cc3b439c SW |
2292 | "with gone raid volume Cmd=0x%2x, TargetId=%d, Lun=%d \n" |
| 2293 | , acb->pci_unit, cmd, target, lun); | |
| 1901a965 SW |
2294 | pccb->ccb_h.status |= CAM_DEV_NOT_THERE; |
| 2295 | arcmsr_srb_complete(srb, 0); | |
| 2296 | return; | |
| 2297 | } | |
| 2298 | } | |
| 2299 | if((pccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { | |
| 2300 | if(nseg != 0) { | |
| 2301 | bus_dmamap_unload(acb->dm_segs_dmat, srb->dm_segs_dmamap); | |
| 2302 | } | |
| 2303 | arcmsr_srb_complete(srb, 0); | |
| 2304 | return; | |
| 2305 | } | |
| 2306 | if(acb->srboutstandingcount >= ARCMSR_MAX_OUTSTANDING_CMD) { | |
| 2307 | xpt_freeze_simq(acb->psim, 1); | |
| 2308 | pccb->ccb_h.status = CAM_REQUEUE_REQ; | |
| 2309 | acb->acb_flags |= ACB_F_CAM_DEV_QFRZN; | |
| 2310 | arcmsr_srb_complete(srb, 0); | |
| 2311 | return; | |
| 2312 | } | |
| 2313 | pccb->ccb_h.status |= CAM_SIM_QUEUED; | |
| 2314 | arcmsr_build_srb(srb, dm_segs, nseg); | |
| 1901a965 | 2315 | arcmsr_post_srb(acb, srb); |
| cc3b439c SW |
2316 | if (pccb->ccb_h.timeout != CAM_TIME_INFINITY) |
| 2317 | { | |
| 2318 | arcmsr_callout_init(&srb->ccb_callout); | |
| 2319 | callout_reset(&srb->ccb_callout, (pccb->ccb_h.timeout * hz ) / 1000, arcmsr_srb_timeout, srb); | |
| 2320 | srb->srb_flags |= SRB_FLAG_TIMER_START; | |
| 2321 | } | |
| 1901a965 SW |
2322 | return; |
| 2323 | } | |
| 2324 | /* | |
| 2325 | ***************************************************************************************** | |
| 2326 | ***************************************************************************************** | |
| 2327 | */ | |
| 2328 | static u_int8_t arcmsr_seek_cmd2abort(union ccb * abortccb) | |
| 2329 | { | |
| 2330 | struct CommandControlBlock *srb; | |
| 2331 | struct AdapterControlBlock *acb=(struct AdapterControlBlock *) abortccb->ccb_h.arcmsr_ccbacb_ptr; | |
| 2332 | u_int32_t intmask_org; | |
| 2333 | int i=0; | |
| 2334 | ||
| 2335 | acb->num_aborts++; | |
| 2336 | /* | |
| 2337 | *************************************************************************** | |
| 2338 | ** It is the upper layer do abort command this lock just prior to calling us. | |
| 2339 | ** First determine if we currently own this command. | |
| 2340 | ** Start by searching the device queue. If not found | |
| 2341 | ** at all, and the system wanted us to just abort the | |
| 2342 | ** command return success. | |
| 2343 | *************************************************************************** | |
| 2344 | */ | |
| 2345 | if(acb->srboutstandingcount!=0) { | |
| cc3b439c SW |
2346 | /* disable all outbound interrupt */ |
| 2347 | intmask_org=arcmsr_disable_allintr(acb); | |
| 1901a965 SW |
2348 | for(i=0;i<ARCMSR_MAX_FREESRB_NUM;i++) { |
| 2349 | srb=acb->psrb_pool[i]; | |
| cc3b439c | 2350 | if(srb->srb_state==ARCMSR_SRB_START) { |
| 1901a965 | 2351 | if(srb->pccb==abortccb) { |
| cc3b439c | 2352 | srb->srb_state=ARCMSR_SRB_ABORTED; |
| 1901a965 SW |
2353 | kprintf("arcmsr%d:scsi id=%d lun=%d abort srb '%p'" |
| 2354 | "outstanding command \n" | |
| 2355 | , acb->pci_unit, abortccb->ccb_h.target_id | |
| 2356 | , abortccb->ccb_h.target_lun, srb); | |
| cc3b439c SW |
2357 | arcmsr_polling_srbdone(acb, srb); |
| 2358 | /* enable outbound Post Queue, outbound doorbell Interrupt */ | |
| 2359 | arcmsr_enable_allintr(acb, intmask_org); | |
| 2360 | return (TRUE); | |
| 1901a965 SW |
2361 | } |
| 2362 | } | |
| 2363 | } | |
| cc3b439c SW |
2364 | /* enable outbound Post Queue, outbound doorbell Interrupt */ |
| 2365 | arcmsr_enable_allintr(acb, intmask_org); | |
| 1901a965 SW |
2366 | } |
| 2367 | return(FALSE); | |
| 1901a965 SW |
2368 | } |
| 2369 | /* | |
| 2370 | **************************************************************************** | |
| 2371 | **************************************************************************** | |
| 2372 | */ | |
| 2373 | static void arcmsr_bus_reset(struct AdapterControlBlock *acb) | |
| 2374 | { | |
| 2375 | int retry=0; | |
| 2376 | ||
| 2377 | acb->num_resets++; | |
| 2378 | acb->acb_flags |=ACB_F_BUS_RESET; | |
| 2379 | while(acb->srboutstandingcount!=0 && retry < 400) { | |
| 2380 | arcmsr_interrupt(acb); | |
| 2381 | UDELAY(25000); | |
| 2382 | retry++; | |
| 2383 | } | |
| 2384 | arcmsr_iop_reset(acb); | |
| 2385 | acb->acb_flags &= ~ACB_F_BUS_RESET; | |
| 2386 | return; | |
| 2387 | } | |
| 2388 | /* | |
| 2389 | ************************************************************************** | |
| 2390 | ************************************************************************** | |
| 2391 | */ | |
| 2392 | static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb, | |
| 2393 | union ccb * pccb) | |
| 2394 | { | |
| 2395 | pccb->ccb_h.status |= CAM_REQ_CMP; | |
| 2396 | switch (pccb->csio.cdb_io.cdb_bytes[0]) { | |
| 2397 | case INQUIRY: { | |
| 2398 | unsigned char inqdata[36]; | |
| 2399 | char *buffer=pccb->csio.data_ptr; | |
| 2400 | ||
| 2401 | if (pccb->ccb_h.target_lun) { | |
| 2402 | pccb->ccb_h.status |= CAM_SEL_TIMEOUT; | |
| 2403 | xpt_done(pccb); | |
| 2404 | return; | |
| 2405 | } | |
| 95696aa4 SW |
2406 | inqdata[0] = T_PROCESSOR; /* Periph Qualifier & Periph Dev Type */ |
| 2407 | inqdata[1] = 0; /* rem media bit & Dev Type Modifier */ | |
| 2408 | inqdata[2] = 0; /* ISO, ECMA, & ANSI versions */ | |
| 2409 | inqdata[3] = 0; | |
| 2410 | inqdata[4] = 31; /* length of additional data */ | |
| 2411 | inqdata[5] = 0; | |
| 2412 | inqdata[6] = 0; | |
| 2413 | inqdata[7] = 0; | |
| 2414 | strncpy(&inqdata[8], "Areca ", 8); /* Vendor Identification */ | |
| 2415 | strncpy(&inqdata[16], "RAID controller ", 16); /* Product Identification */ | |
| 1901a965 SW |
2416 | strncpy(&inqdata[32], "R001", 4); /* Product Revision */ |
| 2417 | memcpy(buffer, inqdata, sizeof(inqdata)); | |
| 2418 | xpt_done(pccb); | |
| 2419 | } | |
| 2420 | break; | |
| 2421 | case WRITE_BUFFER: | |
| 2422 | case READ_BUFFER: { | |
| 2423 | if (arcmsr_iop_message_xfer(acb, pccb)) { | |
| 2424 | pccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; | |
| 2425 | pccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; | |
| 2426 | } | |
| 2427 | xpt_done(pccb); | |
| 2428 | } | |
| 2429 | break; | |
| 2430 | default: | |
| 2431 | xpt_done(pccb); | |
| 2432 | } | |
| 2433 | } | |
| 2434 | /* | |
| 2435 | ********************************************************************* | |
| 2436 | ********************************************************************* | |
| 2437 | */ | |
| 2438 | static void arcmsr_action(struct cam_sim * psim, union ccb * pccb) | |
| 2439 | { | |
| 2440 | struct AdapterControlBlock * acb; | |
| 2441 | ||
| 2442 | acb=(struct AdapterControlBlock *) cam_sim_softc(psim); | |
| 2443 | if(acb==NULL) { | |
| 2444 | pccb->ccb_h.status |= CAM_REQ_INVALID; | |
| 2445 | xpt_done(pccb); | |
| 2446 | return; | |
| 2447 | } | |
| 2448 | switch (pccb->ccb_h.func_code) { | |
| 2449 | case XPT_SCSI_IO: { | |
| 2450 | struct CommandControlBlock *srb; | |
| 2451 | int target=pccb->ccb_h.target_id; | |
| 2452 | ||
| 2453 | if(target == 16) { | |
| 2454 | /* virtual device for iop message transfer */ | |
| 2455 | arcmsr_handle_virtual_command(acb, pccb); | |
| 2456 | return; | |
| 2457 | } | |
| 2458 | if((srb=arcmsr_get_freesrb(acb)) == NULL) { | |
| 2459 | pccb->ccb_h.status |= CAM_RESRC_UNAVAIL; | |
| 2460 | xpt_done(pccb); | |
| 2461 | return; | |
| 2462 | } | |
| 2463 | pccb->ccb_h.arcmsr_ccbsrb_ptr=srb; | |
| 2464 | pccb->ccb_h.arcmsr_ccbacb_ptr=acb; | |
| 2465 | srb->pccb=pccb; | |
| 2466 | if((pccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { | |
| 2467 | if(!(pccb->ccb_h.flags & CAM_SCATTER_VALID)) { | |
| 2468 | /* Single buffer */ | |
| 2469 | if(!(pccb->ccb_h.flags & CAM_DATA_PHYS)) { | |
| 2470 | /* Buffer is virtual */ | |
| 2471 | u_int32_t error; | |
| 2472 | ||
| 2473 | crit_enter(); | |
| 2474 | error = bus_dmamap_load(acb->dm_segs_dmat | |
| 2475 | , srb->dm_segs_dmamap | |
| 2476 | , pccb->csio.data_ptr | |
| 2477 | , pccb->csio.dxfer_len | |
| 95696aa4 | 2478 | , arcmsr_execute_srb, srb, /*flags*/0); |
| 1901a965 SW |
2479 | if(error == EINPROGRESS) { |
| 2480 | xpt_freeze_simq(acb->psim, 1); | |
| 2481 | pccb->ccb_h.status |= CAM_RELEASE_SIMQ; | |
| 2482 | } | |
| 2483 | crit_exit(); | |
| 95696aa4 SW |
2484 | } |
| 2485 | else { /* Buffer is physical */ | |
| 2486 | struct bus_dma_segment seg; | |
| 2487 | ||
| 2488 | seg.ds_addr = (bus_addr_t)pccb->csio.data_ptr; | |
| 2489 | seg.ds_len = pccb->csio.dxfer_len; | |
| 2490 | arcmsr_execute_srb(srb, &seg, 1, 0); | |
| 1901a965 SW |
2491 | } |
| 2492 | } else { | |
| 2493 | /* Scatter/gather list */ | |
| 2494 | struct bus_dma_segment *segs; | |
| 2495 | ||
| 2496 | if((pccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0 | |
| 2497 | || (pccb->ccb_h.flags & CAM_DATA_PHYS) != 0) { | |
| 2498 | pccb->ccb_h.status |= CAM_PROVIDE_FAIL; | |
| 2499 | xpt_done(pccb); | |
| 2500 | kfree(srb, M_DEVBUF); | |
| 2501 | return; | |
| 2502 | } | |
| 2503 | segs=(struct bus_dma_segment *)pccb->csio.data_ptr; | |
| 95696aa4 | 2504 | arcmsr_execute_srb(srb, segs, pccb->csio.sglist_cnt, 0); |
| 1901a965 SW |
2505 | } |
| 2506 | } else { | |
| 95696aa4 | 2507 | arcmsr_execute_srb(srb, NULL, 0, 0); |
| 1901a965 SW |
2508 | } |
| 2509 | break; | |
| 2510 | } | |
| 2511 | case XPT_TARGET_IO: { | |
| 2512 | /* target mode not yet support vendor specific commands. */ | |
| 2513 | pccb->ccb_h.status |= CAM_REQ_CMP; | |
| 2514 | xpt_done(pccb); | |
| 2515 | break; | |
| 2516 | } | |
| 2517 | case XPT_PATH_INQ: { | |
| 2518 | struct ccb_pathinq *cpi= &pccb->cpi; | |
| 2519 | ||
| 2520 | cpi->version_num=1; | |
| 2521 | cpi->hba_inquiry=PI_SDTR_ABLE | PI_TAG_ABLE; | |
| 2522 | cpi->target_sprt=0; | |
| 2523 | cpi->hba_misc=0; | |
| 2524 | cpi->hba_eng_cnt=0; | |
| 2525 | cpi->max_target=ARCMSR_MAX_TARGETID; /* 0-16 */ | |
| 2526 | cpi->max_lun=ARCMSR_MAX_TARGETLUN; /* 0-7 */ | |
| 2527 | cpi->initiator_id=ARCMSR_SCSI_INITIATOR_ID; /* 255 */ | |
| 2528 | cpi->bus_id=cam_sim_bus(psim); | |
| 2529 | strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); | |
| 2530 | strncpy(cpi->hba_vid, "ARCMSR", HBA_IDLEN); | |
| 2531 | strncpy(cpi->dev_name, cam_sim_name(psim), DEV_IDLEN); | |
| 2532 | cpi->unit_number=cam_sim_unit(psim); | |
| 2533 | #ifdef CAM_NEW_TRAN_CODE | |
| 2534 | cpi->transport = XPORT_SPI; | |
| 2535 | cpi->transport_version = 2; | |
| 2536 | cpi->protocol = PROTO_SCSI; | |
| 2537 | cpi->protocol_version = SCSI_REV_2; | |
| 2538 | #endif | |
| 2539 | cpi->ccb_h.status |= CAM_REQ_CMP; | |
| 2540 | xpt_done(pccb); | |
| 2541 | break; | |
| 2542 | } | |
| 2543 | case XPT_ABORT: { | |
| 2544 | union ccb *pabort_ccb; | |
| 2545 | ||
| 2546 | pabort_ccb=pccb->cab.abort_ccb; | |
| 2547 | switch (pabort_ccb->ccb_h.func_code) { | |
| 2548 | case XPT_ACCEPT_TARGET_IO: | |
| 2549 | case XPT_IMMED_NOTIFY: | |
| 2550 | case XPT_CONT_TARGET_IO: | |
| 2551 | if(arcmsr_seek_cmd2abort(pabort_ccb)==TRUE) { | |
| 2552 | pabort_ccb->ccb_h.status |= CAM_REQ_ABORTED; | |
| 2553 | xpt_done(pabort_ccb); | |
| 2554 | pccb->ccb_h.status |= CAM_REQ_CMP; | |
| 2555 | } else { | |
| 2556 | xpt_print_path(pabort_ccb->ccb_h.path); | |
| 2557 | kprintf("Not found\n"); | |
| 2558 | pccb->ccb_h.status |= CAM_PATH_INVALID; | |
| 2559 | } | |
| 2560 | break; | |
| 2561 | case XPT_SCSI_IO: | |
| 2562 | pccb->ccb_h.status |= CAM_UA_ABORT; | |
| 2563 | break; | |
| 2564 | default: | |
| 2565 | pccb->ccb_h.status |= CAM_REQ_INVALID; | |
| 2566 | break; | |
| 2567 | } | |
| 2568 | xpt_done(pccb); | |
| 2569 | break; | |
| 2570 | } | |
| 2571 | case XPT_RESET_BUS: | |
| 2572 | case XPT_RESET_DEV: { | |
| 2573 | u_int32_t i; | |
| 2574 | ||
| 2575 | arcmsr_bus_reset(acb); | |
| 2576 | for (i=0; i < 500; i++) { | |
| 2577 | DELAY(1000); | |
| 2578 | } | |
| 2579 | pccb->ccb_h.status |= CAM_REQ_CMP; | |
| 2580 | xpt_done(pccb); | |
| 2581 | break; | |
| 2582 | } | |
| 2583 | case XPT_TERM_IO: { | |
| 2584 | pccb->ccb_h.status |= CAM_REQ_INVALID; | |
| 2585 | xpt_done(pccb); | |
| 2586 | break; | |
| 2587 | } | |
| 2588 | case XPT_GET_TRAN_SETTINGS: { | |
| 2589 | struct ccb_trans_settings *cts; | |
| 2590 | ||
| 2591 | if(pccb->ccb_h.target_id == 16) { | |
| 2592 | pccb->ccb_h.status |= CAM_FUNC_NOTAVAIL; | |
| 2593 | xpt_done(pccb); | |
| 2594 | break; | |
| 2595 | } | |
| 2596 | cts= &pccb->cts; | |
| 2597 | #ifdef CAM_NEW_TRAN_CODE | |
| 2598 | { | |
| 2599 | struct ccb_trans_settings_scsi *scsi; | |
| 2600 | struct ccb_trans_settings_spi *spi; | |
| 2601 | ||
| 2602 | scsi = &cts->proto_specific.scsi; | |
| 2603 | spi = &cts->xport_specific.spi; | |
| 2604 | cts->protocol = PROTO_SCSI; | |
| 2605 | cts->protocol_version = SCSI_REV_2; | |
| 2606 | cts->transport = XPORT_SPI; | |
| 2607 | cts->transport_version = 2; | |
| 2608 | spi->flags = CTS_SPI_FLAGS_DISC_ENB; | |
| 2609 | spi->sync_period=3; | |
| 2610 | spi->sync_offset=32; | |
| 2611 | spi->bus_width=MSG_EXT_WDTR_BUS_16_BIT; | |
| 2612 | scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; | |
| 2613 | spi->valid = CTS_SPI_VALID_DISC | |
| 2614 | | CTS_SPI_VALID_SYNC_RATE | |
| 2615 | | CTS_SPI_VALID_SYNC_OFFSET | |
| 2616 | | CTS_SPI_VALID_BUS_WIDTH; | |
| 2617 | scsi->valid = CTS_SCSI_VALID_TQ; | |
| 2618 | } | |
| 2619 | #else | |
| 2620 | { | |
| 2621 | cts->flags=(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB); | |
| 2622 | cts->sync_period=3; | |
| 2623 | cts->sync_offset=32; | |
| 2624 | cts->bus_width=MSG_EXT_WDTR_BUS_16_BIT; | |
| 2625 | cts->valid=CCB_TRANS_SYNC_RATE_VALID | | |
| 2626 | CCB_TRANS_SYNC_OFFSET_VALID | | |
| 2627 | CCB_TRANS_BUS_WIDTH_VALID | | |
| 2628 | CCB_TRANS_DISC_VALID | | |
| 2629 | CCB_TRANS_TQ_VALID; | |
| 2630 | } | |
| 2631 | #endif | |
| 2632 | pccb->ccb_h.status |= CAM_REQ_CMP; | |
| 2633 | xpt_done(pccb); | |
| 2634 | break; | |
| 2635 | } | |
| 2636 | case XPT_SET_TRAN_SETTINGS: { | |
| 2637 | pccb->ccb_h.status |= CAM_FUNC_NOTAVAIL; | |
| 2638 | xpt_done(pccb); | |
| 2639 | break; | |
| 2640 | } | |
| 21a3f12e | 2641 | case XPT_CALC_GEOMETRY: |
| 1901a965 SW |
2642 | if(pccb->ccb_h.target_id == 16) { |
| 2643 | pccb->ccb_h.status |= CAM_FUNC_NOTAVAIL; | |
| 2644 | xpt_done(pccb); | |
| 2645 | break; | |
| 2646 | } | |
| 21a3f12e | 2647 | cam_calc_geometry(&pccb->ccg, 1); |
| 1901a965 SW |
2648 | xpt_done(pccb); |
| 2649 | break; | |
| 1901a965 SW |
2650 | default: |
| 2651 | pccb->ccb_h.status |= CAM_REQ_INVALID; | |
| 2652 | xpt_done(pccb); | |
| 2653 | break; | |
| 2654 | } | |
| 2655 | return; | |
| 2656 | } | |
| 2657 | /* | |
| 2658 | ********************************************************************** | |
| 2659 | ********************************************************************** | |
| 2660 | */ | |
| 2661 | static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb) | |
| 2662 | { | |
| 2663 | acb->acb_flags |= ACB_F_MSG_START_BGRB; | |
| 2664 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_START_BGRB); | |
| 2665 | if(!arcmsr_hba_wait_msgint_ready(acb)) { | |
| 2666 | kprintf("arcmsr%d: wait 'start adapter background rebulid' timeout \n", acb->pci_unit); | |
| 2667 | } | |
| 2668 | return; | |
| 2669 | } | |
| 2670 | /* | |
| 2671 | ********************************************************************** | |
| 2672 | ********************************************************************** | |
| 2673 | */ | |
| 2674 | static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb) | |
| 2675 | { | |
| 2676 | acb->acb_flags |= ACB_F_MSG_START_BGRB; | |
| 2677 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_MESSAGE_START_BGRB); | |
| 2678 | if(!arcmsr_hbb_wait_msgint_ready(acb)) { | |
| 2679 | kprintf( "arcmsr%d: wait 'start adapter background rebulid' timeout \n", acb->pci_unit); | |
| 2680 | } | |
| 2681 | return; | |
| 2682 | } | |
| 2683 | /* | |
| 2684 | ********************************************************************** | |
| 2685 | ********************************************************************** | |
| 2686 | */ | |
| 2687 | static void arcmsr_start_hbc_bgrb(struct AdapterControlBlock *acb) | |
| 2688 | { | |
| 2689 | acb->acb_flags |= ACB_F_MSG_START_BGRB; | |
| 2690 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_START_BGRB); | |
| 2691 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE); | |
| 2692 | if(!arcmsr_hbc_wait_msgint_ready(acb)) { | |
| 2693 | kprintf("arcmsr%d: wait 'start adapter background rebulid' timeout \n", acb->pci_unit); | |
| 2694 | } | |
| 2695 | return; | |
| 2696 | } | |
| 2697 | /* | |
| 2698 | ********************************************************************** | |
| 2699 | ********************************************************************** | |
| 2700 | */ | |
| 2701 | static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb) | |
| 2702 | { | |
| 2703 | switch (acb->adapter_type) { | |
| 2704 | case ACB_ADAPTER_TYPE_A: | |
| 2705 | arcmsr_start_hba_bgrb(acb); | |
| 2706 | break; | |
| 2707 | case ACB_ADAPTER_TYPE_B: | |
| 2708 | arcmsr_start_hbb_bgrb(acb); | |
| 2709 | break; | |
| 2710 | case ACB_ADAPTER_TYPE_C: | |
| 2711 | arcmsr_start_hbc_bgrb(acb); | |
| 2712 | break; | |
| 2713 | } | |
| 2714 | return; | |
| 2715 | } | |
| 2716 | /* | |
| 2717 | ********************************************************************** | |
| 2718 | ** | |
| 2719 | ********************************************************************** | |
| 2720 | */ | |
| 2721 | static void arcmsr_polling_hba_srbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_srb) | |
| 2722 | { | |
| 2723 | struct CommandControlBlock *srb; | |
| 2724 | u_int32_t flag_srb, outbound_intstatus, poll_srb_done=0, poll_count=0; | |
| 2725 | u_int16_t error; | |
| 2726 | ||
| 2727 | polling_ccb_retry: | |
| 2728 | poll_count++; | |
| 2729 | outbound_intstatus=CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_intstatus) & acb->outbound_int_enable; | |
| 2730 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intstatus, outbound_intstatus); /*clear interrupt*/ | |
| 2731 | bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); | |
| 2732 | while(1) { | |
| 2733 | if((flag_srb=CHIP_REG_READ32(HBA_MessageUnit, | |
| 2734 | 0, outbound_queueport))==0xFFFFFFFF) { | |
| 2735 | if(poll_srb_done) { | |
| 2736 | break;/*chip FIFO no ccb for completion already*/ | |
| 2737 | } else { | |
| 2738 | UDELAY(25000); | |
| 2739 | if ((poll_count > 100) && (poll_srb != NULL)) { | |
| 2740 | break; | |
| 2741 | } | |
| 2742 | goto polling_ccb_retry; | |
| 2743 | } | |
| 2744 | } | |
| 2745 | /* check if command done with no error*/ | |
| 2746 | srb=(struct CommandControlBlock *) | |
| 2747 | (acb->vir2phy_offset+(flag_srb << 5));/*frame must be 32 bytes aligned*/ | |
| 2748 | error=(flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE0)?TRUE:FALSE; | |
| 2749 | poll_srb_done = (srb==poll_srb) ? 1:0; | |
| cc3b439c SW |
2750 | if((srb->acb!=acb) || (srb->srb_state!=ARCMSR_SRB_START)) { |
| 2751 | if(srb->srb_state==ARCMSR_SRB_ABORTED) { | |
| 1901a965 SW |
2752 | kprintf("arcmsr%d: scsi id=%d lun=%d srb='%p'" |
| 2753 | "poll command abort successfully \n" | |
| 2754 | , acb->pci_unit | |
| 2755 | , srb->pccb->ccb_h.target_id | |
| 2756 | , srb->pccb->ccb_h.target_lun, srb); | |
| 2757 | srb->pccb->ccb_h.status |= CAM_REQ_ABORTED; | |
| 2758 | arcmsr_srb_complete(srb, 1); | |
| 2759 | continue; | |
| 2760 | } | |
| 2761 | kprintf("arcmsr%d: polling get an illegal srb command done srb='%p'" | |
| 2762 | "srboutstandingcount=%d \n" | |
| 2763 | , acb->pci_unit | |
| 2764 | , srb, acb->srboutstandingcount); | |
| 2765 | continue; | |
| 2766 | } | |
| 2767 | arcmsr_report_srb_state(acb, srb, error); | |
| 2768 | } /*drain reply FIFO*/ | |
| 2769 | return; | |
| 2770 | } | |
| 2771 | /* | |
| 2772 | ********************************************************************** | |
| 2773 | ** | |
| 2774 | ********************************************************************** | |
| 2775 | */ | |
| 2776 | static void arcmsr_polling_hbb_srbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_srb) | |
| 2777 | { | |
| 2778 | struct HBB_MessageUnit *phbbmu=(struct HBB_MessageUnit *)acb->pmu; | |
| 2779 | struct CommandControlBlock *srb; | |
| 2780 | u_int32_t flag_srb, poll_srb_done=0, poll_count=0; | |
| 2781 | int index; | |
| 2782 | u_int16_t error; | |
| 2783 | ||
| 2784 | polling_ccb_retry: | |
| 2785 | poll_count++; | |
| 2786 | CHIP_REG_WRITE32(HBB_DOORBELL, | |
| 2787 | 0, iop2drv_doorbell, ARCMSR_DOORBELL_INT_CLEAR_PATTERN); /* clear doorbell interrupt */ | |
| 2788 | bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); | |
| 2789 | while(1) { | |
| 2790 | index=phbbmu->doneq_index; | |
| 2791 | if((flag_srb=phbbmu->done_qbuffer[index]) == 0) { | |
| 2792 | if(poll_srb_done) { | |
| 2793 | break;/*chip FIFO no ccb for completion already*/ | |
| 2794 | } else { | |
| 2795 | UDELAY(25000); | |
| 2796 | if ((poll_count > 100) && (poll_srb != NULL)) { | |
| 2797 | break; | |
| 2798 | } | |
| 2799 | goto polling_ccb_retry; | |
| 2800 | } | |
| 2801 | } | |
| 2802 | phbbmu->done_qbuffer[index]=0; | |
| 2803 | index++; | |
| 2804 | index %= ARCMSR_MAX_HBB_POSTQUEUE; /*if last index number set it to 0 */ | |
| 2805 | phbbmu->doneq_index=index; | |
| 2806 | /* check if command done with no error*/ | |
| 2807 | srb=(struct CommandControlBlock *) | |
| 2808 | (acb->vir2phy_offset+(flag_srb << 5));/*frame must be 32 bytes aligned*/ | |
| 2809 | error=(flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE0)?TRUE:FALSE; | |
| 2810 | poll_srb_done = (srb==poll_srb) ? 1:0; | |
| cc3b439c SW |
2811 | if((srb->acb!=acb) || (srb->srb_state!=ARCMSR_SRB_START)) { |
| 2812 | if(srb->srb_state==ARCMSR_SRB_ABORTED) { | |
| 1901a965 SW |
2813 | kprintf("arcmsr%d: scsi id=%d lun=%d srb='%p'" |
| 2814 | "poll command abort successfully \n" | |
| 2815 | , acb->pci_unit | |
| 2816 | , srb->pccb->ccb_h.target_id | |
| 2817 | , srb->pccb->ccb_h.target_lun, srb); | |
| 2818 | srb->pccb->ccb_h.status |= CAM_REQ_ABORTED; | |
| 2819 | arcmsr_srb_complete(srb, 1); | |
| 2820 | continue; | |
| 2821 | } | |
| 2822 | kprintf("arcmsr%d: polling get an illegal srb command done srb='%p'" | |
| 2823 | "srboutstandingcount=%d \n" | |
| 2824 | , acb->pci_unit | |
| 2825 | , srb, acb->srboutstandingcount); | |
| 2826 | continue; | |
| 2827 | } | |
| 2828 | arcmsr_report_srb_state(acb, srb, error); | |
| 2829 | } /*drain reply FIFO*/ | |
| 2830 | return; | |
| 2831 | } | |
| 2832 | /* | |
| 2833 | ********************************************************************** | |
| 2834 | ** | |
| 2835 | ********************************************************************** | |
| 2836 | */ | |
| 2837 | static void arcmsr_polling_hbc_srbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_srb) | |
| 2838 | { | |
| 2839 | struct CommandControlBlock *srb; | |
| 2840 | u_int32_t flag_srb, poll_srb_done=0, poll_count=0; | |
| 2841 | u_int16_t error; | |
| 2842 | ||
| 2843 | polling_ccb_retry: | |
| 2844 | poll_count++; | |
| 2845 | bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); | |
| 2846 | while(1) { | |
| 2847 | if(!(CHIP_REG_READ32(HBC_MessageUnit, 0, host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR)) { | |
| 2848 | if(poll_srb_done) { | |
| 2849 | break;/*chip FIFO no ccb for completion already*/ | |
| 2850 | } else { | |
| 2851 | UDELAY(25000); | |
| 2852 | if ((poll_count > 100) && (poll_srb != NULL)) { | |
| 2853 | break; | |
| 2854 | } | |
| 2855 | if (acb->srboutstandingcount == 0) { | |
| 2856 | break; | |
| 2857 | } | |
| 2858 | goto polling_ccb_retry; | |
| 2859 | } | |
| 2860 | } | |
| 2861 | flag_srb = CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_queueport_low); | |
| 2862 | /* check if command done with no error*/ | |
| cc3b439c | 2863 | srb=(struct CommandControlBlock *)(acb->vir2phy_offset+(flag_srb & 0xFFFFFFE0));/*frame must be 32 bytes aligned*/ |
| 1901a965 SW |
2864 | error=(flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE1)?TRUE:FALSE; |
| 2865 | if (poll_srb != NULL) | |
| 2866 | poll_srb_done = (srb==poll_srb) ? 1:0; | |
| cc3b439c SW |
2867 | if((srb->acb!=acb) || (srb->srb_state!=ARCMSR_SRB_START)) { |
| 2868 | if(srb->srb_state==ARCMSR_SRB_ABORTED) { | |
| 1901a965 SW |
2869 | kprintf("arcmsr%d: scsi id=%d lun=%d srb='%p'poll command abort successfully \n" |
| 2870 | , acb->pci_unit, srb->pccb->ccb_h.target_id, srb->pccb->ccb_h.target_lun, srb); | |
| 2871 | srb->pccb->ccb_h.status |= CAM_REQ_ABORTED; | |
| 2872 | arcmsr_srb_complete(srb, 1); | |
| 2873 | continue; | |
| 2874 | } | |
| 2875 | kprintf("arcmsr%d: polling get an illegal srb command done srb='%p'srboutstandingcount=%d \n" | |
| 2876 | , acb->pci_unit, srb, acb->srboutstandingcount); | |
| 2877 | continue; | |
| 2878 | } | |
| 2879 | arcmsr_report_srb_state(acb, srb, error); | |
| 2880 | } /*drain reply FIFO*/ | |
| 2881 | return; | |
| 2882 | } | |
| 2883 | /* | |
| 2884 | ********************************************************************** | |
| 2885 | ********************************************************************** | |
| 2886 | */ | |
| 2887 | static void arcmsr_polling_srbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_srb) | |
| 2888 | { | |
| 2889 | switch (acb->adapter_type) { | |
| 2890 | case ACB_ADAPTER_TYPE_A: { | |
| 2891 | arcmsr_polling_hba_srbdone(acb, poll_srb); | |
| 2892 | } | |
| 2893 | break; | |
| 2894 | case ACB_ADAPTER_TYPE_B: { | |
| 2895 | arcmsr_polling_hbb_srbdone(acb, poll_srb); | |
| 2896 | } | |
| 2897 | break; | |
| 2898 | case ACB_ADAPTER_TYPE_C: { | |
| 2899 | arcmsr_polling_hbc_srbdone(acb, poll_srb); | |
| 2900 | } | |
| 2901 | break; | |
| 2902 | } | |
| 2903 | } | |
| 2904 | /* | |
| 2905 | ********************************************************************** | |
| 2906 | ********************************************************************** | |
| 2907 | */ | |
| 2908 | static void arcmsr_get_hba_config(struct AdapterControlBlock *acb) | |
| 2909 | { | |
| 2910 | char *acb_firm_model=acb->firm_model; | |
| 2911 | char *acb_firm_version=acb->firm_version; | |
| 2912 | char *acb_device_map = acb->device_map; | |
| 2913 | size_t iop_firm_model=offsetof(struct HBA_MessageUnit,msgcode_rwbuffer[ARCMSR_FW_MODEL_OFFSET]); /*firm_model,15,60-67*/ | |
| 2914 | size_t iop_firm_version=offsetof(struct HBA_MessageUnit,msgcode_rwbuffer[ARCMSR_FW_VERS_OFFSET]); /*firm_version,17,68-83*/ | |
| 2915 | size_t iop_device_map = offsetof(struct HBA_MessageUnit,msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]); | |
| 2916 | int i; | |
| 2917 | ||
| 2918 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG); | |
| 2919 | if(!arcmsr_hba_wait_msgint_ready(acb)) { | |
| 2920 | kprintf("arcmsr%d: wait 'get adapter firmware miscellaneous data' timeout \n", acb->pci_unit); | |
| 2921 | } | |
| 2922 | i=0; | |
| 2923 | while(i<8) { | |
| 2924 | *acb_firm_model=bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_firm_model+i); | |
| 2925 | /* 8 bytes firm_model, 15, 60-67*/ | |
| 2926 | acb_firm_model++; | |
| 2927 | i++; | |
| 2928 | } | |
| 2929 | i=0; | |
| 2930 | while(i<16) { | |
| 2931 | *acb_firm_version=bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_firm_version+i); | |
| 2932 | /* 16 bytes firm_version, 17, 68-83*/ | |
| 2933 | acb_firm_version++; | |
| 2934 | i++; | |
| 2935 | } | |
| 2936 | i=0; | |
| 2937 | while(i<16) { | |
| 2938 | *acb_device_map=bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_device_map+i); | |
| 2939 | acb_device_map++; | |
| 2940 | i++; | |
| 2941 | } | |
| 2942 | kprintf("ARECA RAID ADAPTER%d: %s \n", acb->pci_unit, ARCMSR_DRIVER_VERSION); | |
| 2943 | kprintf("ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n", acb->pci_unit, acb->firm_version); | |
| 2944 | acb->firm_request_len=CHIP_REG_READ32(HBA_MessageUnit, 0, msgcode_rwbuffer[1]); /*firm_request_len, 1, 04-07*/ | |
| 2945 | acb->firm_numbers_queue=CHIP_REG_READ32(HBA_MessageUnit, 0, msgcode_rwbuffer[2]); /*firm_numbers_queue, 2, 08-11*/ | |
| 2946 | acb->firm_sdram_size=CHIP_REG_READ32(HBA_MessageUnit, 0, msgcode_rwbuffer[3]); /*firm_sdram_size, 3, 12-15*/ | |
| 2947 | acb->firm_ide_channels=CHIP_REG_READ32(HBA_MessageUnit, 0, msgcode_rwbuffer[4]); /*firm_ide_channels, 4, 16-19*/ | |
| 2948 | acb->firm_cfg_version=CHIP_REG_READ32(HBA_MessageUnit, 0, msgcode_rwbuffer[ARCMSR_FW_CFGVER_OFFSET]); /*firm_cfg_version, 25, */ | |
| 2949 | return; | |
| 2950 | } | |
| 2951 | /* | |
| 2952 | ********************************************************************** | |
| 2953 | ********************************************************************** | |
| 2954 | */ | |
| 2955 | static void arcmsr_get_hbb_config(struct AdapterControlBlock *acb) | |
| 2956 | { | |
| 2957 | char *acb_firm_model=acb->firm_model; | |
| 2958 | char *acb_firm_version=acb->firm_version; | |
| 2959 | char *acb_device_map = acb->device_map; | |
| 2960 | size_t iop_firm_model=offsetof(struct HBB_RWBUFFER, msgcode_rwbuffer[ARCMSR_FW_MODEL_OFFSET]); /*firm_model,15,60-67*/ | |
| 2961 | size_t iop_firm_version=offsetof(struct HBB_RWBUFFER, msgcode_rwbuffer[ARCMSR_FW_VERS_OFFSET]); /*firm_version,17,68-83*/ | |
| 2962 | size_t iop_device_map = offsetof(struct HBB_RWBUFFER, msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]); | |
| 2963 | int i; | |
| 2964 | ||
| 2965 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_MESSAGE_GET_CONFIG); | |
| 2966 | if(!arcmsr_hbb_wait_msgint_ready(acb)) { | |
| 2967 | kprintf( "arcmsr%d: wait" "'get adapter firmware miscellaneous data' timeout \n", acb->pci_unit); | |
| 2968 | } | |
| 2969 | i=0; | |
| 2970 | while(i<8) { | |
| 2971 | *acb_firm_model=bus_space_read_1(acb->btag[1], acb->bhandle[1], iop_firm_model+i); | |
| 2972 | /* 8 bytes firm_model, 15, 60-67*/ | |
| 2973 | acb_firm_model++; | |
| 2974 | i++; | |
| 2975 | } | |
| 2976 | i=0; | |
| 2977 | while(i<16) { | |
| 2978 | *acb_firm_version=bus_space_read_1(acb->btag[1], acb->bhandle[1], iop_firm_version+i); | |
| 2979 | /* 16 bytes firm_version, 17, 68-83*/ | |
| 2980 | acb_firm_version++; | |
| 2981 | i++; | |
| 2982 | } | |
| 2983 | i=0; | |
| 2984 | while(i<16) { | |
| 2985 | *acb_device_map=bus_space_read_1(acb->btag[1], acb->bhandle[1], iop_device_map+i); | |
| 2986 | acb_device_map++; | |
| 2987 | i++; | |
| 2988 | } | |
| 2989 | kprintf("ARECA RAID ADAPTER%d: %s \n", acb->pci_unit, ARCMSR_DRIVER_VERSION); | |
| 2990 | kprintf("ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n", acb->pci_unit, acb->firm_version); | |
| 2991 | acb->firm_request_len=CHIP_REG_READ32(HBB_RWBUFFER, 1, msgcode_rwbuffer[1]); /*firm_request_len, 1, 04-07*/ | |
| 2992 | acb->firm_numbers_queue=CHIP_REG_READ32(HBB_RWBUFFER, 1, msgcode_rwbuffer[2]); /*firm_numbers_queue, 2, 08-11*/ | |
| 2993 | acb->firm_sdram_size=CHIP_REG_READ32(HBB_RWBUFFER, 1, msgcode_rwbuffer[3]); /*firm_sdram_size, 3, 12-15*/ | |
| 2994 | acb->firm_ide_channels=CHIP_REG_READ32(HBB_RWBUFFER, 1, msgcode_rwbuffer[4]); /*firm_ide_channels, 4, 16-19*/ | |
| 2995 | acb->firm_cfg_version=CHIP_REG_READ32(HBB_RWBUFFER, 1, msgcode_rwbuffer[ARCMSR_FW_CFGVER_OFFSET]); /*firm_cfg_version, 25, */ | |
| 2996 | return; | |
| 2997 | } | |
| 2998 | /* | |
| 2999 | ********************************************************************** | |
| 3000 | ********************************************************************** | |
| 3001 | */ | |
| 3002 | static void arcmsr_get_hbc_config(struct AdapterControlBlock *acb) | |
| 3003 | { | |
| 3004 | char *acb_firm_model=acb->firm_model; | |
| 3005 | char *acb_firm_version=acb->firm_version; | |
| 3006 | char *acb_device_map = acb->device_map; | |
| 3007 | size_t iop_firm_model=offsetof(struct HBC_MessageUnit,msgcode_rwbuffer[ARCMSR_FW_MODEL_OFFSET]); /*firm_model,15,60-67*/ | |
| 3008 | size_t iop_firm_version=offsetof(struct HBC_MessageUnit,msgcode_rwbuffer[ARCMSR_FW_VERS_OFFSET]); /*firm_version,17,68-83*/ | |
| 3009 | size_t iop_device_map = offsetof(struct HBC_MessageUnit,msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]); | |
| 3010 | int i; | |
| 3011 | ||
| 3012 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG); | |
| 3013 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE); | |
| 3014 | if(!arcmsr_hbc_wait_msgint_ready(acb)) { | |
| 3015 | kprintf("arcmsr%d: wait 'get adapter firmware miscellaneous data' timeout \n", acb->pci_unit); | |
| 3016 | } | |
| 3017 | i=0; | |
| 3018 | while(i<8) { | |
| 3019 | *acb_firm_model=bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_firm_model+i); | |
| 3020 | /* 8 bytes firm_model, 15, 60-67*/ | |
| 3021 | acb_firm_model++; | |
| 3022 | i++; | |
| 3023 | } | |
| 3024 | i=0; | |
| 3025 | while(i<16) { | |
| 3026 | *acb_firm_version=bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_firm_version+i); | |
| 3027 | /* 16 bytes firm_version, 17, 68-83*/ | |
| 3028 | acb_firm_version++; | |
| 3029 | i++; | |
| 3030 | } | |
| 3031 | i=0; | |
| 3032 | while(i<16) { | |
| 3033 | *acb_device_map=bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_device_map+i); | |
| 3034 | acb_device_map++; | |
| 3035 | i++; | |
| 3036 | } | |
| 3037 | kprintf("ARECA RAID ADAPTER%d: %s \n", acb->pci_unit, ARCMSR_DRIVER_VERSION); | |
| 3038 | kprintf("ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n", acb->pci_unit, acb->firm_version); | |
| 3039 | acb->firm_request_len =CHIP_REG_READ32(HBC_MessageUnit, 0, msgcode_rwbuffer[1]); /*firm_request_len, 1, 04-07*/ | |
| 3040 | acb->firm_numbers_queue =CHIP_REG_READ32(HBC_MessageUnit, 0, msgcode_rwbuffer[2]); /*firm_numbers_queue, 2, 08-11*/ | |
| 3041 | acb->firm_sdram_size =CHIP_REG_READ32(HBC_MessageUnit, 0, msgcode_rwbuffer[3]); /*firm_sdram_size, 3, 12-15*/ | |
| 3042 | acb->firm_ide_channels =CHIP_REG_READ32(HBC_MessageUnit, 0, msgcode_rwbuffer[4]); /*firm_ide_channels, 4, 16-19*/ | |
| 3043 | acb->firm_cfg_version =CHIP_REG_READ32(HBC_MessageUnit, 0, msgcode_rwbuffer[ARCMSR_FW_CFGVER_OFFSET]); /*firm_cfg_version, 25, */ | |
| 3044 | return; | |
| 3045 | } | |
| 3046 | /* | |
| 3047 | ********************************************************************** | |
| 3048 | ********************************************************************** | |
| 3049 | */ | |
| 3050 | static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb) | |
| 3051 | { | |
| 3052 | switch (acb->adapter_type) { | |
| 3053 | case ACB_ADAPTER_TYPE_A: { | |
| 3054 | arcmsr_get_hba_config(acb); | |
| 3055 | } | |
| 3056 | break; | |
| 3057 | case ACB_ADAPTER_TYPE_B: { | |
| 3058 | arcmsr_get_hbb_config(acb); | |
| 3059 | } | |
| 3060 | break; | |
| 3061 | case ACB_ADAPTER_TYPE_C: { | |
| 3062 | arcmsr_get_hbc_config(acb); | |
| 3063 | } | |
| 3064 | break; | |
| 3065 | } | |
| 3066 | return; | |
| 3067 | } | |
| 3068 | /* | |
| 3069 | ********************************************************************** | |
| 3070 | ********************************************************************** | |
| 3071 | */ | |
| 3072 | static void arcmsr_wait_firmware_ready( struct AdapterControlBlock *acb) | |
| 3073 | { | |
| 3074 | int timeout=0; | |
| 3075 | ||
| 3076 | switch (acb->adapter_type) { | |
| 3077 | case ACB_ADAPTER_TYPE_A: { | |
| 3078 | while ((CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) | |
| 3079 | { | |
| 3080 | if (timeout++ > 2000) /* (2000*15)/1000 = 30 sec */ | |
| 3081 | { | |
| 3082 | kprintf( "arcmsr%d:timed out waiting for firmware \n", acb->pci_unit); | |
| 3083 | return; | |
| 3084 | } | |
| 3085 | UDELAY(15000); /* wait 15 milli-seconds */ | |
| 3086 | } | |
| 3087 | } | |
| 3088 | break; | |
| 3089 | case ACB_ADAPTER_TYPE_B: { | |
| 3090 | while ((CHIP_REG_READ32(HBB_DOORBELL, 0, iop2drv_doorbell) & ARCMSR_MESSAGE_FIRMWARE_OK) == 0) | |
| 3091 | { | |
| 3092 | if (timeout++ > 2000) /* (2000*15)/1000 = 30 sec */ | |
| 3093 | { | |
| 3094 | kprintf( "arcmsr%d: timed out waiting for firmware \n", acb->pci_unit); | |
| 3095 | return; | |
| 3096 | } | |
| 3097 | UDELAY(15000); /* wait 15 milli-seconds */ | |
| 3098 | } | |
| 3099 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_DRV2IOP_END_OF_INTERRUPT); | |
| 3100 | } | |
| 3101 | break; | |
| 3102 | case ACB_ADAPTER_TYPE_C: { | |
| 3103 | while ((CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_msgaddr1) & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0) | |
| 3104 | { | |
| 3105 | if (timeout++ > 2000) /* (2000*15)/1000 = 30 sec */ | |
| 3106 | { | |
| 3107 | kprintf( "arcmsr%d:timed out waiting for firmware ready\n", acb->pci_unit); | |
| 3108 | return; | |
| 3109 | } | |
| 3110 | UDELAY(15000); /* wait 15 milli-seconds */ | |
| 3111 | } | |
| 3112 | } | |
| 3113 | break; | |
| 3114 | } | |
| 3115 | return; | |
| 3116 | } | |
| 3117 | /* | |
| 3118 | ********************************************************************** | |
| 3119 | ********************************************************************** | |
| 3120 | */ | |
| 3121 | static void arcmsr_clear_doorbell_queue_buffer( struct AdapterControlBlock *acb) | |
| 3122 | { | |
| 3123 | u_int32_t outbound_doorbell; | |
| 3124 | ||
| 3125 | switch (acb->adapter_type) { | |
| 3126 | case ACB_ADAPTER_TYPE_A: { | |
| 3127 | /* empty doorbell Qbuffer if door bell ringed */ | |
| 3128 | outbound_doorbell = CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_doorbell); | |
| 3129 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_doorbell, outbound_doorbell); /*clear doorbell interrupt */ | |
| 3130 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_READ_OK); | |
| 3131 | ||
| 3132 | } | |
| 3133 | break; | |
| 3134 | case ACB_ADAPTER_TYPE_B: { | |
| 3135 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, iop2drv_doorbell, ARCMSR_MESSAGE_INT_CLEAR_PATTERN);/*clear interrupt and message state*/ | |
| 3136 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_DRV2IOP_DATA_READ_OK); | |
| 3137 | /* let IOP know data has been read */ | |
| 3138 | } | |
| 3139 | break; | |
| 3140 | case ACB_ADAPTER_TYPE_C: { | |
| 3141 | /* empty doorbell Qbuffer if door bell ringed */ | |
| 3142 | outbound_doorbell = CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_doorbell); | |
| 3143 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, outbound_doorbell_clear, outbound_doorbell); /*clear doorbell interrupt */ | |
| 3144 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK); | |
| 3145 | ||
| 3146 | } | |
| 3147 | break; | |
| 3148 | } | |
| 3149 | return; | |
| 3150 | } | |
| 3151 | /* | |
| 3152 | ************************************************************************ | |
| 3153 | ************************************************************************ | |
| 3154 | */ | |
| 3155 | static u_int32_t arcmsr_iop_confirm(struct AdapterControlBlock *acb) | |
| 3156 | { | |
| 3157 | unsigned long srb_phyaddr; | |
| 3158 | u_int32_t srb_phyaddr_hi32; | |
| 3159 | ||
| 3160 | /* | |
| 3161 | ******************************************************************** | |
| 3162 | ** here we need to tell iop 331 our freesrb.HighPart | |
| 3163 | ** if freesrb.HighPart is not zero | |
| 3164 | ******************************************************************** | |
| 3165 | */ | |
| 3166 | srb_phyaddr= (unsigned long) acb->srb_phyaddr.phyaddr; | |
| 3167 | // srb_phyaddr_hi32=(u_int32_t) ((srb_phyaddr>>16)>>16); | |
| 3168 | srb_phyaddr_hi32=acb->srb_phyaddr.B.phyadd_high; | |
| 3169 | switch (acb->adapter_type) { | |
| 3170 | case ACB_ADAPTER_TYPE_A: { | |
| 3171 | if(srb_phyaddr_hi32!=0) { | |
| 3172 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, msgcode_rwbuffer[0], ARCMSR_SIGNATURE_SET_CONFIG); | |
| 3173 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, msgcode_rwbuffer[1], srb_phyaddr_hi32); | |
| 3174 | CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_SET_CONFIG); | |
| 3175 | if(!arcmsr_hba_wait_msgint_ready(acb)) { | |
| 3176 | kprintf( "arcmsr%d: 'set srb high part physical address' timeout \n", acb->pci_unit); | |
| 3177 | return FALSE; | |
| 3178 | } | |
| 3179 | } | |
| 3180 | } | |
| 3181 | break; | |
| 3182 | /* | |
| 3183 | *********************************************************************** | |
| 3184 | ** if adapter type B, set window of "post command Q" | |
| 3185 | *********************************************************************** | |
| 3186 | */ | |
| 3187 | case ACB_ADAPTER_TYPE_B: { | |
| 3188 | u_int32_t post_queue_phyaddr; | |
| 3189 | struct HBB_MessageUnit *phbbmu; | |
| 3190 | ||
| 3191 | phbbmu=(struct HBB_MessageUnit *)acb->pmu; | |
| 3192 | phbbmu->postq_index=0; | |
| 3193 | phbbmu->doneq_index=0; | |
| 3194 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_MESSAGE_SET_POST_WINDOW); | |
| 3195 | if(!arcmsr_hbb_wait_msgint_ready(acb)) { | |
| 3196 | kprintf( "arcmsr%d: 'set window of post command Q' timeout\n", acb->pci_unit); | |
| 3197 | return FALSE; | |
| 3198 | } | |
| cc3b439c | 3199 | post_queue_phyaddr = srb_phyaddr + ARCMSR_SRBS_POOL_SIZE |
| 1901a965 SW |
3200 | + offsetof(struct HBB_MessageUnit, post_qbuffer); |
| 3201 | CHIP_REG_WRITE32(HBB_RWBUFFER, 1, msgcode_rwbuffer[0], ARCMSR_SIGNATURE_SET_CONFIG); /* driver "set config" signature */ | |
| 3202 | CHIP_REG_WRITE32(HBB_RWBUFFER, 1, msgcode_rwbuffer[1], srb_phyaddr_hi32); /* normal should be zero */ | |
| 3203 | CHIP_REG_WRITE32(HBB_RWBUFFER, 1, msgcode_rwbuffer[2], post_queue_phyaddr); /* postQ size (256+8)*4 */ | |
| 3204 | CHIP_REG_WRITE32(HBB_RWBUFFER, 1, msgcode_rwbuffer[3], post_queue_phyaddr+1056); /* doneQ size (256+8)*4 */ | |
| 3205 | CHIP_REG_WRITE32(HBB_RWBUFFER, 1, msgcode_rwbuffer[4], 1056); /* srb maxQ size must be --> [(256+8)*4] */ | |
| 3206 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_MESSAGE_SET_CONFIG); | |
| 3207 | if(!arcmsr_hbb_wait_msgint_ready(acb)) { | |
| 3208 | kprintf( "arcmsr%d: 'set command Q window' timeout \n", acb->pci_unit); | |
| 3209 | return FALSE; | |
| 3210 | } | |
| 3211 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell, ARCMSR_MESSAGE_START_DRIVER_MODE); | |
| 3212 | if(!arcmsr_hbb_wait_msgint_ready(acb)) { | |
| 3213 | kprintf( "arcmsr%d: 'start diver mode' timeout \n", acb->pci_unit); | |
| 3214 | return FALSE; | |
| 3215 | } | |
| 3216 | } | |
| 3217 | break; | |
| 3218 | case ACB_ADAPTER_TYPE_C: { | |
| 3219 | if(srb_phyaddr_hi32!=0) { | |
| 3220 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, msgcode_rwbuffer[0], ARCMSR_SIGNATURE_SET_CONFIG); | |
| 3221 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, msgcode_rwbuffer[1], srb_phyaddr_hi32); | |
| 3222 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_SET_CONFIG); | |
| 3223 | CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell,ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE); | |
| 3224 | if(!arcmsr_hbc_wait_msgint_ready(acb)) { | |
| 3225 | kprintf( "arcmsr%d: 'set srb high part physical address' timeout \n", acb->pci_unit); | |
| 3226 | return FALSE; | |
| 3227 | } | |
| 3228 | } | |
| 3229 | } | |
| 3230 | break; | |
| 3231 | } | |
| 3232 | return TRUE; | |
| 3233 | } | |
| 3234 | /* | |
| 3235 | ************************************************************************ | |
| 3236 | ************************************************************************ | |
| 3237 | */ | |
| 3238 | static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb) | |
| 3239 | { | |
| 3240 | switch (acb->adapter_type) | |
| 3241 | { | |
| 3242 | case ACB_ADAPTER_TYPE_A: | |
| 3243 | case ACB_ADAPTER_TYPE_C: | |
| 3244 | break; | |
| 3245 | case ACB_ADAPTER_TYPE_B: { | |
| 3246 | CHIP_REG_WRITE32(HBB_DOORBELL, 0, drv2iop_doorbell,ARCMSR_MESSAGE_ACTIVE_EOI_MODE); | |
| 3247 | if(!arcmsr_hbb_wait_msgint_ready(acb)) { | |
| 3248 | kprintf( "arcmsr%d: 'iop enable eoi mode' timeout \n", acb->pci_unit); | |
| 3249 | ||
| 3250 | return; | |
| 3251 | } | |
| 3252 | } | |
| 3253 | break; | |
| 3254 | } | |
| 3255 | return; | |
| 3256 | } | |
| 3257 | /* | |
| 3258 | ********************************************************************** | |
| 3259 | ********************************************************************** | |
| 3260 | */ | |
| 3261 | static void arcmsr_iop_init(struct AdapterControlBlock *acb) | |
| 3262 | { | |
| 3263 | u_int32_t intmask_org; | |
| 3264 | ||
| 3265 | /* disable all outbound interrupt */ | |
| 3266 | intmask_org=arcmsr_disable_allintr(acb); | |
| 3267 | arcmsr_wait_firmware_ready(acb); | |
| 3268 | arcmsr_iop_confirm(acb); | |
| 3269 | arcmsr_get_firmware_spec(acb); | |
| 3270 | /*start background rebuild*/ | |
| 3271 | arcmsr_start_adapter_bgrb(acb); | |
| 3272 | /* empty doorbell Qbuffer if door bell ringed */ | |
| 3273 | arcmsr_clear_doorbell_queue_buffer(acb); | |
| 3274 | arcmsr_enable_eoi_mode(acb); | |
| 3275 | /* enable outbound Post Queue, outbound doorbell Interrupt */ | |
| 3276 | arcmsr_enable_allintr(acb, intmask_org); | |
| 3277 | acb->acb_flags |=ACB_F_IOP_INITED; | |
| 3278 | return; | |
| 3279 | } | |
| 3280 | /* | |
| 3281 | ********************************************************************** | |
| 3282 | ********************************************************************** | |
| 3283 | */ | |
| 95696aa4 | 3284 | static void arcmsr_map_free_srb(void *arg, bus_dma_segment_t *segs, int nseg, int error) |
| 1901a965 SW |
3285 | { |
| 3286 | struct AdapterControlBlock *acb=arg; | |
| 3287 | struct CommandControlBlock *srb_tmp; | |
| 3288 | u_int8_t * dma_memptr; | |
| 3289 | u_int32_t i; | |
| 3290 | unsigned long srb_phyaddr=(unsigned long)segs->ds_addr; | |
| 3291 | ||
| 3292 | dma_memptr=acb->uncacheptr; | |
| 3293 | acb->srb_phyaddr.phyaddr=srb_phyaddr; | |
| 3294 | srb_tmp=(struct CommandControlBlock *)dma_memptr; | |
| 3295 | for(i=0;i<ARCMSR_MAX_FREESRB_NUM;i++) { | |
| 3296 | if(bus_dmamap_create(acb->dm_segs_dmat, | |
| 3297 | /*flags*/0, &srb_tmp->dm_segs_dmamap)!=0) { | |
| 3298 | acb->acb_flags |= ACB_F_MAPFREESRB_FAILD; | |
| 3299 | kprintf("arcmsr%d:" | |
| 3300 | " srb dmamap bus_dmamap_create error\n", acb->pci_unit); | |
| 3301 | return; | |
| 3302 | } | |
| 3303 | srb_tmp->cdb_shifted_phyaddr=(acb->adapter_type==ACB_ADAPTER_TYPE_C)?srb_phyaddr:(srb_phyaddr >> 5); | |
| 3304 | srb_tmp->acb=acb; | |
| 3305 | acb->srbworkingQ[i]=acb->psrb_pool[i]=srb_tmp; | |
| cc3b439c SW |
3306 | srb_phyaddr=srb_phyaddr+SRB_SIZE; |
| 3307 | srb_tmp = (struct CommandControlBlock *)((unsigned long)srb_tmp+SRB_SIZE); | |
| 1901a965 | 3308 | } |
| 362298e4 | 3309 | acb->vir2phy_offset=(unsigned long)srb_tmp-srb_phyaddr; |
| 1901a965 SW |
3310 | return; |
| 3311 | } | |
| 3312 | /* | |
| 3313 | ************************************************************************ | |
| 3314 | ** | |
| 3315 | ** | |
| 3316 | ************************************************************************ | |
| 3317 | */ | |
| 3318 | static void arcmsr_free_resource(struct AdapterControlBlock *acb) | |
| 3319 | { | |
| 3320 | /* remove the control device */ | |
| 3321 | if(acb->ioctl_dev != NULL) { | |
| 3322 | destroy_dev(acb->ioctl_dev); | |
| 3323 | } | |
| 3324 | bus_dmamap_unload(acb->srb_dmat, acb->srb_dmamap); | |
| 3325 | bus_dmamap_destroy(acb->srb_dmat, acb->srb_dmamap); | |
| 3326 | bus_dma_tag_destroy(acb->srb_dmat); | |
| 3327 | bus_dma_tag_destroy(acb->dm_segs_dmat); | |
| 3328 | bus_dma_tag_destroy(acb->parent_dmat); | |
| 3329 | return; | |
| 3330 | } | |
| 3331 | /* | |
| 3332 | ************************************************************************ | |
| 3333 | ************************************************************************ | |
| 3334 | */ | |
| 3335 | static u_int32_t arcmsr_initialize(device_t dev) | |
| 3336 | { | |
| 3337 | struct AdapterControlBlock *acb=device_get_softc(dev); | |
| 3338 | u_int16_t pci_command; | |
| 3339 | int i, j,max_coherent_size; | |
| 3340 | ||
| 3341 | switch (pci_get_devid(dev)) { | |
| 3342 | case PCIDevVenIDARC1880: { | |
| 3343 | acb->adapter_type=ACB_ADAPTER_TYPE_C; | |
| 3344 | max_coherent_size=ARCMSR_SRBS_POOL_SIZE; | |
| 3345 | } | |
| 3346 | break; | |
| 95696aa4 | 3347 | case PCIDevVenIDARC1200: |
| 1901a965 SW |
3348 | case PCIDevVenIDARC1201: { |
| 3349 | acb->adapter_type=ACB_ADAPTER_TYPE_B; | |
| 3350 | max_coherent_size=ARCMSR_SRBS_POOL_SIZE+(sizeof(struct HBB_MessageUnit)); | |
| 3351 | } | |
| 3352 | break; | |
| 3353 | case PCIDevVenIDARC1110: | |
| 3354 | case PCIDevVenIDARC1120: | |
| 3355 | case PCIDevVenIDARC1130: | |
| 3356 | case PCIDevVenIDARC1160: | |
| 3357 | case PCIDevVenIDARC1170: | |
| 3358 | case PCIDevVenIDARC1210: | |
| 3359 | case PCIDevVenIDARC1220: | |
| 3360 | case PCIDevVenIDARC1230: | |
| 95696aa4 | 3361 | case PCIDevVenIDARC1231: |
| 1901a965 | 3362 | case PCIDevVenIDARC1260: |
| 95696aa4 | 3363 | case PCIDevVenIDARC1261: |
| 1901a965 SW |
3364 | case PCIDevVenIDARC1270: |
| 3365 | case PCIDevVenIDARC1280: | |
| 3366 | case PCIDevVenIDARC1212: | |
| 3367 | case PCIDevVenIDARC1222: | |
| 3368 | case PCIDevVenIDARC1380: | |
| 3369 | case PCIDevVenIDARC1381: | |
| 3370 | case PCIDevVenIDARC1680: | |
| 3371 | case PCIDevVenIDARC1681: { | |
| 3372 | acb->adapter_type=ACB_ADAPTER_TYPE_A; | |
| 3373 | max_coherent_size=ARCMSR_SRBS_POOL_SIZE; | |
| 3374 | } | |
| 3375 | break; | |
| 3376 | default: { | |
| 3377 | kprintf("arcmsr%d:" | |
| 3378 | " unknown RAID adapter type \n", device_get_unit(dev)); | |
| 3379 | return ENOMEM; | |
| 3380 | } | |
| 3381 | } | |
| 3382 | if(bus_dma_tag_create( /*parent*/ NULL, | |
| 3383 | /*alignemnt*/ 1, | |
| 3384 | /*boundary*/ 0, | |
| 3385 | /*lowaddr*/ BUS_SPACE_MAXADDR, | |
| 3386 | /*highaddr*/ BUS_SPACE_MAXADDR, | |
| 3387 | /*filter*/ NULL, | |
| 3388 | /*filterarg*/ NULL, | |
| 3389 | /*maxsize*/ BUS_SPACE_MAXSIZE_32BIT, | |
| 3390 | /*nsegments*/ BUS_SPACE_UNRESTRICTED, | |
| 3391 | /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, | |
| 3392 | /*flags*/ 0, | |
| 3393 | &acb->parent_dmat) != 0) | |
| 3394 | { | |
| 3395 | kprintf("arcmsr%d: parent_dmat bus_dma_tag_create failure!\n", device_get_unit(dev)); | |
| 3396 | return ENOMEM; | |
| 3397 | } | |
| 3398 | /* Create a single tag describing a region large enough to hold all of the s/g lists we will need. */ | |
| 3399 | if(bus_dma_tag_create( /*parent_dmat*/ acb->parent_dmat, | |
| 3400 | /*alignment*/ 1, | |
| 3401 | /*boundary*/ 0, | |
| 3402 | /*lowaddr*/ BUS_SPACE_MAXADDR, | |
| 3403 | /*highaddr*/ BUS_SPACE_MAXADDR, | |
| 3404 | /*filter*/ NULL, | |
| 3405 | /*filterarg*/ NULL, | |
| 95696aa4 | 3406 | /*maxsize*/ ARCMSR_MAX_SG_ENTRIES * PAGE_SIZE * ARCMSR_MAX_FREESRB_NUM, |
| 1901a965 SW |
3407 | /*nsegments*/ ARCMSR_MAX_SG_ENTRIES, |
| 3408 | /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, | |
| 3409 | /*flags*/ 0, | |
| 3410 | &acb->dm_segs_dmat) != 0) | |
| 3411 | { | |
| 3412 | bus_dma_tag_destroy(acb->parent_dmat); | |
| 3413 | kprintf("arcmsr%d: dm_segs_dmat bus_dma_tag_create failure!\n", device_get_unit(dev)); | |
| 3414 | return ENOMEM; | |
| 3415 | } | |
| 3416 | /* DMA tag for our srb structures.... Allocate the freesrb memory */ | |
| 3417 | if(bus_dma_tag_create( /*parent_dmat*/ acb->parent_dmat, | |
| 3418 | /*alignment*/ 0x20, | |
| 3419 | /*boundary*/ 0, | |
| 3420 | /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT, | |
| 3421 | /*highaddr*/ BUS_SPACE_MAXADDR, | |
| 3422 | /*filter*/ NULL, | |
| 3423 | /*filterarg*/ NULL, | |
| 3424 | /*maxsize*/ max_coherent_size, | |
| 3425 | /*nsegments*/ 1, | |
| 3426 | /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, | |
| 3427 | /*flags*/ 0, | |
| 3428 | &acb->srb_dmat) != 0) | |
| 3429 | { | |
| 3430 | bus_dma_tag_destroy(acb->dm_segs_dmat); | |
| 3431 | bus_dma_tag_destroy(acb->parent_dmat); | |
| 3432 | kprintf("arcmsr%d: srb_dmat bus_dma_tag_create failure!\n", device_get_unit(dev)); | |
| 3433 | return ENXIO; | |
| 3434 | } | |
| 3435 | /* Allocation for our srbs */ | |
| 3436 | if(bus_dmamem_alloc(acb->srb_dmat, (void **)&acb->uncacheptr, BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, &acb->srb_dmamap) != 0) { | |
| 3437 | bus_dma_tag_destroy(acb->srb_dmat); | |
| 3438 | bus_dma_tag_destroy(acb->dm_segs_dmat); | |
| 3439 | bus_dma_tag_destroy(acb->parent_dmat); | |
| 3440 | kprintf("arcmsr%d: srb_dmat bus_dmamem_alloc failure!\n", device_get_unit(dev)); | |
| 3441 | return ENXIO; | |
| 3442 | } | |
| 3443 | /* And permanently map them */ | |
| 95696aa4 | 3444 | if(bus_dmamap_load(acb->srb_dmat, acb->srb_dmamap, acb->uncacheptr, max_coherent_size, arcmsr_map_free_srb, acb, /*flags*/0)) { |
| 1901a965 SW |
3445 | bus_dma_tag_destroy(acb->srb_dmat); |
| 3446 | bus_dma_tag_destroy(acb->dm_segs_dmat); | |
| 3447 | bus_dma_tag_destroy(acb->parent_dmat); | |
| 3448 | kprintf("arcmsr%d: srb_dmat bus_dmamap_load failure!\n", device_get_unit(dev)); | |
| 3449 | return ENXIO; | |
| 3450 | } | |
| 3451 | pci_command=pci_read_config(dev, PCIR_COMMAND, 2); | |
| 3452 | pci_command |= PCIM_CMD_BUSMASTEREN; | |
| 3453 | pci_command |= PCIM_CMD_PERRESPEN; | |
| 3454 | pci_command |= PCIM_CMD_MWRICEN; | |
| 3455 | /* Enable Busmaster/Mem */ | |
| 3456 | pci_command |= PCIM_CMD_MEMEN; | |
| 3457 | pci_write_config(dev, PCIR_COMMAND, pci_command, 2); | |
| 3458 | switch(acb->adapter_type) { | |
| 3459 | case ACB_ADAPTER_TYPE_A: { | |
| 3460 | u_int32_t rid0=PCIR_BAR(0); | |
| 3461 | vm_offset_t mem_base0; | |
| 3462 | ||
| 3463 | acb->sys_res_arcmsr[0]=bus_alloc_resource(dev,SYS_RES_MEMORY, &rid0, 0ul, ~0ul, 0x1000, RF_ACTIVE); | |
| 3464 | if(acb->sys_res_arcmsr[0] == NULL) { | |
| 3465 | arcmsr_free_resource(acb); | |
| 3466 | kprintf("arcmsr%d: bus_alloc_resource failure!\n", device_get_unit(dev)); | |
| 3467 | return ENOMEM; | |
| 3468 | } | |
| 3469 | if(rman_get_start(acb->sys_res_arcmsr[0]) <= 0) { | |
| 3470 | arcmsr_free_resource(acb); | |
| 3471 | kprintf("arcmsr%d: rman_get_start failure!\n", device_get_unit(dev)); | |
| 3472 | return ENXIO; | |
| 3473 | } | |
| 3474 | mem_base0=(vm_offset_t) rman_get_virtual(acb->sys_res_arcmsr[0]); | |
| 3475 | if(mem_base0==0) { | |
| 3476 | arcmsr_free_resource(acb); | |
| 3477 | kprintf("arcmsr%d: rman_get_virtual failure!\n", device_get_unit(dev)); | |
| 3478 | return ENXIO; | |
| 3479 | } | |
| 3480 | acb->btag[0]=rman_get_bustag(acb->sys_res_arcmsr[0]); | |
| 3481 | acb->bhandle[0]=rman_get_bushandle(acb->sys_res_arcmsr[0]); | |
| 3482 | acb->pmu=(struct MessageUnit_UNION *)mem_base0; | |
| 3483 | } | |
| 3484 | break; | |
| 3485 | case ACB_ADAPTER_TYPE_B: { | |
| 3486 | struct HBB_MessageUnit *phbbmu; | |
| 3487 | struct CommandControlBlock *freesrb; | |
| 3488 | u_int32_t rid[]={ PCIR_BAR(0), PCIR_BAR(2) }; | |
| 3489 | vm_offset_t mem_base[]={0,0}; | |
| 3490 | for(i=0; i<2; i++) { | |
| 3491 | if(i==0) { | |
| 3492 | acb->sys_res_arcmsr[i]=bus_alloc_resource(dev,SYS_RES_MEMORY, &rid[i], | |
| 95696aa4 | 3493 | 0ul, ~0ul, sizeof(struct HBB_DOORBELL), RF_ACTIVE); |
| 1901a965 SW |
3494 | } else { |
| 3495 | acb->sys_res_arcmsr[i]=bus_alloc_resource(dev, SYS_RES_MEMORY, &rid[i], | |
| 95696aa4 | 3496 | 0ul, ~0ul, sizeof(struct HBB_RWBUFFER), RF_ACTIVE); |
| 1901a965 SW |
3497 | } |
| 3498 | if(acb->sys_res_arcmsr[i] == NULL) { | |
| 3499 | arcmsr_free_resource(acb); | |
| 3500 | kprintf("arcmsr%d: bus_alloc_resource %d failure!\n", device_get_unit(dev), i); | |
| 3501 | return ENOMEM; | |
| 3502 | } | |
| 3503 | if(rman_get_start(acb->sys_res_arcmsr[i]) <= 0) { | |
| 3504 | arcmsr_free_resource(acb); | |
| 3505 | kprintf("arcmsr%d: rman_get_start %d failure!\n", device_get_unit(dev), i); | |
| 3506 | return ENXIO; | |
| 3507 | } | |
| 3508 | mem_base[i]=(vm_offset_t) rman_get_virtual(acb->sys_res_arcmsr[i]); | |
| 3509 | if(mem_base[i]==0) { | |
| 3510 | arcmsr_free_resource(acb); | |
| 3511 | kprintf("arcmsr%d: rman_get_virtual %d failure!\n", device_get_unit(dev), i); | |
| 3512 | return ENXIO; | |
| 3513 | } | |
| 3514 | acb->btag[i]=rman_get_bustag(acb->sys_res_arcmsr[i]); | |
| 3515 | acb->bhandle[i]=rman_get_bushandle(acb->sys_res_arcmsr[i]); | |
| 3516 | } | |
| 3517 | freesrb=(struct CommandControlBlock *)acb->uncacheptr; | |
| cc3b439c SW |
3518 | // acb->pmu=(struct MessageUnit_UNION *)&freesrb[ARCMSR_MAX_FREESRB_NUM]; |
| 3519 | acb->pmu=(struct MessageUnit_UNION *)((unsigned long)freesrb+ARCMSR_SRBS_POOL_SIZE); | |
| 1901a965 SW |
3520 | phbbmu=(struct HBB_MessageUnit *)acb->pmu; |
| 3521 | phbbmu->hbb_doorbell=(struct HBB_DOORBELL *)mem_base[0]; | |
| 3522 | phbbmu->hbb_rwbuffer=(struct HBB_RWBUFFER *)mem_base[1]; | |
| 3523 | } | |
| 3524 | break; | |
| 3525 | case ACB_ADAPTER_TYPE_C: { | |
| 3526 | u_int32_t rid0=PCIR_BAR(1); | |
| 3527 | vm_offset_t mem_base0; | |
| 3528 | ||
| 3529 | acb->sys_res_arcmsr[0]=bus_alloc_resource(dev,SYS_RES_MEMORY, &rid0, 0ul, ~0ul, sizeof(struct HBC_MessageUnit), RF_ACTIVE); | |
| 3530 | if(acb->sys_res_arcmsr[0] == NULL) { | |
| 3531 | arcmsr_free_resource(acb); | |
| 3532 | kprintf("arcmsr%d: bus_alloc_resource failure!\n", device_get_unit(dev)); | |
| 3533 | return ENOMEM; | |
| 3534 | } | |
| 3535 | if(rman_get_start(acb->sys_res_arcmsr[0]) <= 0) { | |
| 3536 | arcmsr_free_resource(acb); | |
| 3537 | kprintf("arcmsr%d: rman_get_start failure!\n", device_get_unit(dev)); | |
| 3538 | return ENXIO; | |
| 3539 | } | |
| 3540 | mem_base0=(vm_offset_t) rman_get_virtual(acb->sys_res_arcmsr[0]); | |
| 3541 | if(mem_base0==0) { | |
| 3542 | arcmsr_free_resource(acb); | |
| 3543 | kprintf("arcmsr%d: rman_get_virtual failure!\n", device_get_unit(dev)); | |
| 3544 | return ENXIO; | |
| 3545 | } | |
| 3546 | acb->btag[0]=rman_get_bustag(acb->sys_res_arcmsr[0]); | |
| 3547 | acb->bhandle[0]=rman_get_bushandle(acb->sys_res_arcmsr[0]); | |
| 3548 | acb->pmu=(struct MessageUnit_UNION *)mem_base0; | |
| 3549 | } | |
| 3550 | break; | |
| 3551 | } | |
| 3552 | if(acb->acb_flags & ACB_F_MAPFREESRB_FAILD) { | |
| 3553 | arcmsr_free_resource(acb); | |
| 3554 | kprintf("arcmsr%d: map free srb failure!\n", device_get_unit(dev)); | |
| 3555 | return ENXIO; | |
| 3556 | } | |
| 3557 | acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED|ACB_F_MESSAGE_RQBUFFER_CLEARED|ACB_F_MESSAGE_WQBUFFER_READ); | |
| 3558 | acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER; | |
| 3559 | /* | |
| 3560 | ******************************************************************** | |
| 3561 | ** init raid volume state | |
| 3562 | ******************************************************************** | |
| 3563 | */ | |
| 3564 | for(i=0;i<ARCMSR_MAX_TARGETID;i++) { | |
| 3565 | for(j=0;j<ARCMSR_MAX_TARGETLUN;j++) { | |
| 3566 | acb->devstate[i][j]=ARECA_RAID_GONE; | |
| 3567 | } | |
| 3568 | } | |
| 3569 | arcmsr_iop_init(acb); | |
| 3570 | return(0); | |
| 3571 | } | |
| 3572 | /* | |
| 3573 | ************************************************************************ | |
| 3574 | ************************************************************************ | |
| 3575 | */ | |
| 3576 | static int arcmsr_attach(device_t dev) | |
| 3577 | { | |
| 3578 | struct AdapterControlBlock *acb=(struct AdapterControlBlock *)device_get_softc(dev); | |
| 3579 | u_int32_t unit=device_get_unit(dev); | |
| 3580 | struct ccb_setasync csa; | |
| 3581 | struct cam_devq *devq; /* Device Queue to use for this SIM */ | |
| 3582 | struct resource *irqres; | |
| 3583 | int rid; | |
| fb8c9539 | 3584 | u_int irq_flags; |
| 1901a965 SW |
3585 | |
| 3586 | if(acb == NULL) { | |
| 3587 | kprintf("arcmsr%d: cannot allocate softc\n", unit); | |
| 3588 | return (ENOMEM); | |
| 3589 | } | |
| 3590 | ARCMSR_LOCK_INIT(&acb->qbuffer_lock, "arcmsr Q buffer lock"); | |
| 3591 | if(arcmsr_initialize(dev)) { | |
| 3592 | kprintf("arcmsr%d: initialize failure!\n", unit); | |
| 3593 | ARCMSR_LOCK_DESTROY(&acb->qbuffer_lock); | |
| 3594 | return ENXIO; | |
| 3595 | } | |
| 3596 | /* After setting up the adapter, map our interrupt */ | |
| 3597 | rid=0; | |
| fb8c9539 SW |
3598 | acb->irq_type = pci_alloc_1intr(dev, arcmsr_msi_enable, &rid, |
| 3599 | &irq_flags); | |
| 3600 | irqres=bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0ul, ~0ul, 1, | |
| 3601 | irq_flags); | |
| 1901a965 | 3602 | if(irqres == NULL || |
| 5746be3d | 3603 | bus_setup_intr(dev, irqres, INTR_MPSAFE, arcmsr_intr_handler, acb, &acb->ih, NULL)) { |
| 1901a965 SW |
3604 | arcmsr_free_resource(acb); |
| 3605 | ARCMSR_LOCK_DESTROY(&acb->qbuffer_lock); | |
| 3606 | kprintf("arcmsr%d: unable to register interrupt handler!\n", unit); | |
| 3607 | return ENXIO; | |
| 3608 | } | |
| 3609 | acb->irqres=irqres; | |
| 3610 | acb->pci_dev=dev; | |
| 3611 | acb->pci_unit=unit; | |
| 3612 | /* | |
| 3613 | * Now let the CAM generic SCSI layer find the SCSI devices on | |
| 3614 | * the bus * start queue to reset to the idle loop. * | |
| 3615 | * Create device queue of SIM(s) * (MAX_START_JOB - 1) : | |
| 3616 | * max_sim_transactions | |
| 3617 | */ | |
| 3618 | devq=cam_simq_alloc(ARCMSR_MAX_START_JOB); | |
| 3619 | if(devq == NULL) { | |
| 3620 | arcmsr_free_resource(acb); | |
| 3621 | bus_release_resource(dev, SYS_RES_IRQ, 0, acb->irqres); | |
| fb8c9539 | 3622 | if (acb->irq_type == PCI_INTR_TYPE_MSI) |
| 0e51efc7 | 3623 | pci_release_msi(dev); |
| 1901a965 SW |
3624 | ARCMSR_LOCK_DESTROY(&acb->qbuffer_lock); |
| 3625 | kprintf("arcmsr%d: cam_simq_alloc failure!\n", unit); | |
| 3626 | return ENXIO; | |
| 3627 | } | |
| 3628 | acb->psim=cam_sim_alloc(arcmsr_action, arcmsr_poll, "arcmsr", acb, unit, &acb->qbuffer_lock, 1, ARCMSR_MAX_OUTSTANDING_CMD, devq); | |
| 3629 | if(acb->psim == NULL) { | |
| 3630 | arcmsr_free_resource(acb); | |
| 3631 | bus_release_resource(dev, SYS_RES_IRQ, 0, acb->irqres); | |
| fb8c9539 | 3632 | if (acb->irq_type == PCI_INTR_TYPE_MSI) |
| 0e51efc7 | 3633 | pci_release_msi(dev); |
| 1cfe5c66 | 3634 | cam_simq_release(devq); |
| 1901a965 SW |
3635 | ARCMSR_LOCK_DESTROY(&acb->qbuffer_lock); |
| 3636 | kprintf("arcmsr%d: cam_sim_alloc failure!\n", unit); | |
| 3637 | return ENXIO; | |
| 3638 | } | |
| 3639 | ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); | |
| 3640 | if(xpt_bus_register(acb->psim, 0) != CAM_SUCCESS) { | |
| 3641 | arcmsr_free_resource(acb); | |
| 3642 | bus_release_resource(dev, SYS_RES_IRQ, 0, acb->irqres); | |
| fb8c9539 | 3643 | if (acb->irq_type == PCI_INTR_TYPE_MSI) |
| 0e51efc7 | 3644 | pci_release_msi(dev); |
| 1901a965 SW |
3645 | cam_sim_free(acb->psim); |
| 3646 | ARCMSR_LOCK_DESTROY(&acb->qbuffer_lock); | |
| 3647 | kprintf("arcmsr%d: xpt_bus_register failure!\n", unit); | |
| 3648 | return ENXIO; | |
| 3649 | } | |
| 3650 | if(xpt_create_path(&acb->ppath, /* periph */ NULL, cam_sim_path(acb->psim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { | |
| 3651 | arcmsr_free_resource(acb); | |
| 3652 | bus_release_resource(dev, SYS_RES_IRQ, 0, acb->irqres); | |
| fb8c9539 | 3653 | if (acb->irq_type == PCI_INTR_TYPE_MSI) |
| 0e51efc7 | 3654 | pci_release_msi(dev); |
| 1901a965 SW |
3655 | xpt_bus_deregister(cam_sim_path(acb->psim)); |
| 3656 | cam_sim_free(acb->psim); | |
| 3657 | ARCMSR_LOCK_DESTROY(&acb->qbuffer_lock); | |
| 3658 | kprintf("arcmsr%d: xpt_create_path failure!\n", unit); | |
| 3659 | return ENXIO; | |
| 3660 | } | |
| 3661 | /* | |
| 3662 | **************************************************** | |
| 3663 | */ | |
| 3664 | xpt_setup_ccb(&csa.ccb_h, acb->ppath, /*priority*/5); | |
| 3665 | csa.ccb_h.func_code=XPT_SASYNC_CB; | |
| 3666 | csa.event_enable=AC_FOUND_DEVICE|AC_LOST_DEVICE; | |
| 3667 | csa.callback=arcmsr_async; | |
| 3668 | csa.callback_arg=acb->psim; | |
| 3669 | xpt_action((union ccb *)&csa); | |
| 3670 | ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); | |
| 3671 | /* Create the control device. */ | |
| 3672 | acb->ioctl_dev=make_dev(&arcmsr_ops, unit, UID_ROOT, GID_WHEEL /* GID_OPERATOR */, S_IRUSR | S_IWUSR, "arcmsr%d", unit); | |
| 3673 | ||
| 3674 | acb->ioctl_dev->si_drv1=acb; | |
| 1901a965 | 3675 | (void)make_dev_alias(acb->ioctl_dev, "arc%d", unit); |
| cc3b439c | 3676 | arcmsr_callout_init(&acb->devmap_callout); |
| 1901a965 SW |
3677 | callout_reset(&acb->devmap_callout, 60 * hz, arcmsr_polling_devmap, acb); |
| 3678 | return 0; | |
| 3679 | } | |
| cc3b439c | 3680 | |
| 1901a965 SW |
3681 | /* |
| 3682 | ************************************************************************ | |
| 3683 | ************************************************************************ | |
| 3684 | */ | |
| 3685 | static int arcmsr_probe(device_t dev) | |
| 3686 | { | |
| 3687 | u_int32_t id; | |
| 3688 | static char buf[256]; | |
| 95696aa4 | 3689 | char x_type[]={"X-TYPE"}; |
| 1901a965 SW |
3690 | char *type; |
| 3691 | int raid6 = 1; | |
| 3692 | ||
| 3693 | if (pci_get_vendor(dev) != PCI_VENDOR_ID_ARECA) { | |
| 3694 | return (ENXIO); | |
| 3695 | } | |
| 3696 | switch(id=pci_get_devid(dev)) { | |
| 3697 | case PCIDevVenIDARC1110: | |
| 95696aa4 | 3698 | case PCIDevVenIDARC1200: |
| 1901a965 | 3699 | case PCIDevVenIDARC1201: |
| 95696aa4 | 3700 | case PCIDevVenIDARC1210: |
| 1901a965 SW |
3701 | raid6 = 0; |
| 3702 | /*FALLTHRU*/ | |
| 3703 | case PCIDevVenIDARC1120: | |
| 3704 | case PCIDevVenIDARC1130: | |
| 3705 | case PCIDevVenIDARC1160: | |
| 3706 | case PCIDevVenIDARC1170: | |
| 3707 | case PCIDevVenIDARC1220: | |
| 3708 | case PCIDevVenIDARC1230: | |
| 95696aa4 | 3709 | case PCIDevVenIDARC1231: |
| 1901a965 | 3710 | case PCIDevVenIDARC1260: |
| 95696aa4 | 3711 | case PCIDevVenIDARC1261: |
| 1901a965 SW |
3712 | case PCIDevVenIDARC1270: |
| 3713 | case PCIDevVenIDARC1280: | |
| 3714 | type = "SATA"; | |
| 3715 | break; | |
| 3716 | case PCIDevVenIDARC1212: | |
| 3717 | case PCIDevVenIDARC1222: | |
| 3718 | case PCIDevVenIDARC1380: | |
| 3719 | case PCIDevVenIDARC1381: | |
| 3720 | case PCIDevVenIDARC1680: | |
| 3721 | case PCIDevVenIDARC1681: | |
| 3722 | type = "SAS 3G"; | |
| 3723 | break; | |
| 3724 | case PCIDevVenIDARC1880: | |
| 3725 | type = "SAS 6G"; | |
| ad8f657d | 3726 | arcmsr_msi_enable = 0; |
| 1901a965 SW |
3727 | break; |
| 3728 | default: | |
| 95696aa4 | 3729 | type = x_type; |
| 1901a965 SW |
3730 | break; |
| 3731 | } | |
| 95696aa4 SW |
3732 | if(type == x_type) |
| 3733 | return(ENXIO); | |
| 10072aca | 3734 | ksprintf(buf, "Areca %s Host Adapter RAID Controller%s", type, raid6 ? " (RAID6 capable)" : ""); |
| 1901a965 SW |
3735 | device_set_desc_copy(dev, buf); |
| 3736 | return 0; | |
| 3737 | } | |
| 3738 | /* | |
| 3739 | ************************************************************************ | |
| 3740 | ************************************************************************ | |
| 3741 | */ | |
| 3742 | static int arcmsr_shutdown(device_t dev) | |
| 3743 | { | |
| 3744 | u_int32_t i; | |
| 3745 | u_int32_t intmask_org; | |
| 3746 | struct CommandControlBlock *srb; | |
| 3747 | struct AdapterControlBlock *acb=(struct AdapterControlBlock *)device_get_softc(dev); | |
| 3748 | ||
| 3749 | /* stop adapter background rebuild */ | |
| 3750 | ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); | |
| 3751 | /* disable all outbound interrupt */ | |
| 3752 | intmask_org=arcmsr_disable_allintr(acb); | |
| 3753 | arcmsr_stop_adapter_bgrb(acb); | |
| 3754 | arcmsr_flush_adapter_cache(acb); | |
| 3755 | /* abort all outstanding command */ | |
| 3756 | acb->acb_flags |= ACB_F_SCSISTOPADAPTER; | |
| 3757 | acb->acb_flags &= ~ACB_F_IOP_INITED; | |
| 3758 | if(acb->srboutstandingcount!=0) { | |
| 3759 | /*clear and abort all outbound posted Q*/ | |
| 3760 | arcmsr_done4abort_postqueue(acb); | |
| 3761 | /* talk to iop 331 outstanding command aborted*/ | |
| 3762 | arcmsr_abort_allcmd(acb); | |
| 3763 | for(i=0;i<ARCMSR_MAX_FREESRB_NUM;i++) { | |
| 3764 | srb=acb->psrb_pool[i]; | |
| cc3b439c SW |
3765 | if(srb->srb_state==ARCMSR_SRB_START) { |
| 3766 | srb->srb_state=ARCMSR_SRB_ABORTED; | |
| 1901a965 SW |
3767 | srb->pccb->ccb_h.status |= CAM_REQ_ABORTED; |
| 3768 | arcmsr_srb_complete(srb, 1); | |
| 3769 | } | |
| 3770 | } | |
| 3771 | } | |
| cc3b439c | 3772 | acb->srboutstandingcount=0; |
| 1901a965 SW |
3773 | acb->workingsrb_doneindex=0; |
| 3774 | acb->workingsrb_startindex=0; | |
| cc3b439c SW |
3775 | #ifdef ARCMSR_DEBUG1 |
| 3776 | acb->pktRequestCount = 0; | |
| 3777 | acb->pktReturnCount = 0; | |
| 3778 | #endif | |
| 1901a965 SW |
3779 | ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); |
| 3780 | return (0); | |
| 3781 | } | |
| 3782 | /* | |
| 3783 | ************************************************************************ | |
| 3784 | ************************************************************************ | |
| 3785 | */ | |
| 3786 | static int arcmsr_detach(device_t dev) | |
| 3787 | { | |
| 3788 | struct AdapterControlBlock *acb=(struct AdapterControlBlock *)device_get_softc(dev); | |
| 3789 | int i; | |
| 3790 | ||
| 3791 | callout_stop(&acb->devmap_callout); | |
| 3792 | bus_teardown_intr(dev, acb->irqres, acb->ih); | |
| 3793 | arcmsr_shutdown(dev); | |
| 3794 | arcmsr_free_resource(acb); | |
| 3795 | for(i=0; (acb->sys_res_arcmsr[i]!=NULL) && (i<2); i++) { | |
| 3796 | bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(i), acb->sys_res_arcmsr[i]); | |
| 3797 | } | |
| 3798 | bus_release_resource(dev, SYS_RES_IRQ, 0, acb->irqres); | |
| fb8c9539 | 3799 | if (acb->irq_type == PCI_INTR_TYPE_MSI) |
| 0e51efc7 | 3800 | pci_release_msi(dev); |
| 1901a965 SW |
3801 | ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); |
| 3802 | xpt_async(AC_LOST_DEVICE, acb->ppath, NULL); | |
| 3803 | xpt_free_path(acb->ppath); | |
| 3804 | xpt_bus_deregister(cam_sim_path(acb->psim)); | |
| 3805 | cam_sim_free(acb->psim); | |
| 3806 | ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); | |
| 3807 | ARCMSR_LOCK_DESTROY(&acb->qbuffer_lock); | |
| 3808 | return (0); | |
| 3809 | } | |
| cc3b439c SW |
3810 | |
| 3811 | #ifdef ARCMSR_DEBUG1 | |
| 3812 | static void arcmsr_dump_data(struct AdapterControlBlock *acb) | |
| 3813 | { | |
| 3814 | if((acb->pktRequestCount - acb->pktReturnCount) == 0) | |
| 3815 | return; | |
| 3816 | printf("Command Request Count =0x%x\n",acb->pktRequestCount); | |
| 3817 | printf("Command Return Count =0x%x\n",acb->pktReturnCount); | |
| 3818 | printf("Command (Req-Rtn) Count =0x%x\n",(acb->pktRequestCount - acb->pktReturnCount)); | |
| 3819 | printf("Queued Command Count =0x%x\n",acb->srboutstandingcount); | |
| 3820 | } | |
| 3821 | #endif |