12aedd662SScott Long /*- 2aad970f1SDavid E. O'Brien * Written by: David Jeffery 32aedd662SScott Long * Copyright (c) 2002 Adaptec Inc. 42aedd662SScott Long * All rights reserved. 52aedd662SScott Long * 62aedd662SScott Long * Redistribution and use in source and binary forms, with or without 72aedd662SScott Long * modification, are permitted provided that the following conditions 82aedd662SScott Long * are met: 92aedd662SScott Long * 1. Redistributions of source code must retain the above copyright 102aedd662SScott Long * notice, this list of conditions and the following disclaimer. 112aedd662SScott Long * 2. Redistributions in binary form must reproduce the above copyright 122aedd662SScott Long * notice, this list of conditions and the following disclaimer in the 132aedd662SScott Long * documentation and/or other materials provided with the distribution. 142aedd662SScott Long * 152aedd662SScott Long * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 162aedd662SScott Long * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 172aedd662SScott Long * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 182aedd662SScott Long * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 192aedd662SScott Long * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 202aedd662SScott Long * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 212aedd662SScott Long * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 222aedd662SScott Long * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 232aedd662SScott Long * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 242aedd662SScott Long * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 252aedd662SScott Long * SUCH DAMAGE. 262aedd662SScott Long */ 272aedd662SScott Long 28aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 29aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 302aedd662SScott Long 312aedd662SScott Long #include <dev/ips/ips.h> 322aedd662SScott Long #include <sys/stat.h> 332aedd662SScott Long #include <sys/time.h> 342aedd662SScott Long #include <machine/clock.h> 352aedd662SScott Long 362aedd662SScott Long static d_open_t ips_open; 372aedd662SScott Long static d_close_t ips_close; 382aedd662SScott Long static d_ioctl_t ips_ioctl; 392aedd662SScott Long 402aedd662SScott Long #define IPS_CDEV_MAJOR 175 412aedd662SScott Long static struct cdevsw ips_cdevsw = { 422aedd662SScott Long .d_open = ips_open, 432aedd662SScott Long .d_close = ips_close, 442aedd662SScott Long .d_ioctl = ips_ioctl, 452aedd662SScott Long .d_name = "ips", 462aedd662SScott Long .d_maj = IPS_CDEV_MAJOR, 472aedd662SScott Long }; 482aedd662SScott Long 492aedd662SScott Long 502aedd662SScott Long static int ips_open(dev_t dev, int flags, int fmt, struct thread *td) 512aedd662SScott Long { 522aedd662SScott Long ips_softc_t *sc = dev->si_drv1; 532aedd662SScott Long sc->state |= IPS_DEV_OPEN; 542aedd662SScott Long return 0; 552aedd662SScott Long } 562aedd662SScott Long 572aedd662SScott Long static int ips_close(dev_t dev, int flags, int fmt, struct thread *td) 582aedd662SScott Long { 592aedd662SScott Long ips_softc_t *sc = dev->si_drv1; 602aedd662SScott Long sc->state &= ~IPS_DEV_OPEN; 612aedd662SScott Long 622aedd662SScott Long return 0; 632aedd662SScott Long } 642aedd662SScott Long 652aedd662SScott Long static int ips_ioctl(dev_t dev, u_long command, caddr_t addr, int32_t flags, struct thread *td) 662aedd662SScott Long { 672aedd662SScott Long ips_softc_t *sc; 682aedd662SScott Long 692aedd662SScott Long sc = dev->si_drv1; 702aedd662SScott Long return ips_ioctl_request(sc, command, addr, flags); 712aedd662SScott Long } 722aedd662SScott Long 732aedd662SScott Long static void ips_cmd_dmaload(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) 742aedd662SScott Long { 752aedd662SScott Long ips_command_t *command = cmdptr; 762aedd662SScott Long PRINTF(10, "ips: in ips_cmd_dmaload\n"); 772aedd662SScott Long if(!error) 782aedd662SScott Long command->command_phys_addr = segments[0].ds_addr; 792aedd662SScott Long 802aedd662SScott Long } 812aedd662SScott Long 822aedd662SScott Long /* is locking needed? what locking guarentees are there on removal? */ 832aedd662SScott Long static __inline__ int ips_cmdqueue_free(ips_softc_t *sc) 842aedd662SScott Long { 852aedd662SScott Long int i, error = -1; 862aedd662SScott Long intrmask_t mask = splbio(); 872aedd662SScott Long if(!sc->used_commands){ 882aedd662SScott Long for(i = 0; i < sc->max_cmds; i++){ 892aedd662SScott Long if(!(sc->commandarray[i].command_phys_addr)) 902aedd662SScott Long continue; 912aedd662SScott Long bus_dmamap_unload(sc->command_dmatag, 922aedd662SScott Long sc->commandarray[i].command_dmamap); 932aedd662SScott Long bus_dmamem_free(sc->command_dmatag, 942aedd662SScott Long sc->commandarray[i].command_buffer, 952aedd662SScott Long sc->commandarray[i].command_dmamap); 962aedd662SScott Long } 972aedd662SScott Long error = 0; 982aedd662SScott Long sc->state |= IPS_OFFLINE; 992aedd662SScott Long } 1002aedd662SScott Long splx(mask); 1012aedd662SScott Long return error; 1022aedd662SScott Long } 1032aedd662SScott Long 1042aedd662SScott Long /* places all ips command structs on the free command queue. No locking as if someone else tries 1052aedd662SScott Long * to access this during init, we have bigger problems */ 1062aedd662SScott Long static __inline__ int ips_cmdqueue_init(ips_softc_t *sc) 1072aedd662SScott Long { 1082aedd662SScott Long int i; 1092aedd662SScott Long ips_command_t *command; 1102aedd662SScott Long SLIST_INIT(&sc->free_cmd_list); 1112aedd662SScott Long STAILQ_INIT(&sc->cmd_wait_list); 1122aedd662SScott Long for(i = 0; i < sc->max_cmds; i++){ 1132aedd662SScott Long sc->commandarray[i].id = i; 1142aedd662SScott Long sc->commandarray[i].sc = sc; 1152aedd662SScott Long SLIST_INSERT_HEAD(&sc->free_cmd_list, &sc->commandarray[i], 1162aedd662SScott Long next); 1172aedd662SScott Long } 1182aedd662SScott Long for(i = 0; i < sc->max_cmds; i++){ 1192aedd662SScott Long command = &sc->commandarray[i]; 1202aedd662SScott Long if(bus_dmamem_alloc(sc->command_dmatag,&command->command_buffer, 1212aedd662SScott Long BUS_DMA_NOWAIT, &command->command_dmamap)) 1222aedd662SScott Long goto error; 1232aedd662SScott Long bus_dmamap_load(sc->command_dmatag, command->command_dmamap, 1242aedd662SScott Long command->command_buffer,IPS_COMMAND_LEN, 1252aedd662SScott Long ips_cmd_dmaload, command, BUS_DMA_NOWAIT); 1262aedd662SScott Long if(!command->command_phys_addr){ 1272aedd662SScott Long bus_dmamem_free(sc->command_dmatag, 1282aedd662SScott Long command->command_buffer, command->command_dmamap); 1292aedd662SScott Long goto error; 1302aedd662SScott Long } 1312aedd662SScott Long } 1322aedd662SScott Long sc->state &= ~IPS_OFFLINE; 1332aedd662SScott Long return 0; 1342aedd662SScott Long error: 1352aedd662SScott Long ips_cmdqueue_free(sc); 1362aedd662SScott Long return ENOMEM; 1372aedd662SScott Long } 1382aedd662SScott Long 1392aedd662SScott Long static int ips_add_waiting_command(ips_softc_t *sc, int (*callback)(ips_command_t *), void *data, unsigned long flags) 1402aedd662SScott Long { 1412aedd662SScott Long intrmask_t mask; 1422aedd662SScott Long ips_command_t *command; 1432aedd662SScott Long ips_wait_list_t *waiter; 1442aedd662SScott Long unsigned long memflags = 0; 1452aedd662SScott Long if(IPS_NOWAIT_FLAG & flags) 1462aedd662SScott Long memflags = M_NOWAIT; 1472aedd662SScott Long waiter = malloc(sizeof(ips_wait_list_t), M_DEVBUF, memflags); 1482aedd662SScott Long if(!waiter) 1492aedd662SScott Long return ENOMEM; 1502aedd662SScott Long mask = splbio(); 1512aedd662SScott Long if(sc->state & IPS_OFFLINE){ 1522aedd662SScott Long splx(mask); 1532aedd662SScott Long return EIO; 1542aedd662SScott Long } 1552aedd662SScott Long command = SLIST_FIRST(&sc->free_cmd_list); 1562aedd662SScott Long if(command && !(sc->state & IPS_TIMEOUT)){ 1572aedd662SScott Long SLIST_REMOVE_HEAD(&sc->free_cmd_list, next); 1582aedd662SScott Long (sc->used_commands)++; 1592aedd662SScott Long splx(mask); 1602aedd662SScott Long clear_ips_command(command); 1612aedd662SScott Long bzero(command->command_buffer, IPS_COMMAND_LEN); 1622aedd662SScott Long free(waiter, M_DEVBUF); 1632aedd662SScott Long command->arg = data; 1642aedd662SScott Long return callback(command); 1652aedd662SScott Long } 1662aedd662SScott Long DEVICE_PRINTF(1, sc->dev, "adding command to the wait queue\n"); 1672aedd662SScott Long waiter->callback = callback; 1682aedd662SScott Long waiter->data = data; 1692aedd662SScott Long STAILQ_INSERT_TAIL(&sc->cmd_wait_list, waiter, next); 1702aedd662SScott Long splx(mask); 1712aedd662SScott Long return 0; 1722aedd662SScott Long } 1732aedd662SScott Long 1742aedd662SScott Long static void ips_run_waiting_command(ips_softc_t *sc) 1752aedd662SScott Long { 1762aedd662SScott Long ips_wait_list_t *waiter; 1772aedd662SScott Long ips_command_t *command; 1782aedd662SScott Long int (*callback)(ips_command_t*); 1792aedd662SScott Long intrmask_t mask; 1802aedd662SScott Long 1812aedd662SScott Long mask = splbio(); 1822aedd662SScott Long waiter = STAILQ_FIRST(&sc->cmd_wait_list); 1832aedd662SScott Long command = SLIST_FIRST(&sc->free_cmd_list); 1842aedd662SScott Long if(!waiter || !command){ 1852aedd662SScott Long splx(mask); 1862aedd662SScott Long return; 1872aedd662SScott Long } 1882aedd662SScott Long DEVICE_PRINTF(1, sc->dev, "removing command from wait queue\n"); 1892aedd662SScott Long SLIST_REMOVE_HEAD(&sc->free_cmd_list, next); 1902aedd662SScott Long STAILQ_REMOVE_HEAD(&sc->cmd_wait_list, next); 1912aedd662SScott Long (sc->used_commands)++; 1922aedd662SScott Long splx(mask); 1932aedd662SScott Long clear_ips_command(command); 1942aedd662SScott Long bzero(command->command_buffer, IPS_COMMAND_LEN); 1952aedd662SScott Long command->arg = waiter->data; 1962aedd662SScott Long callback = waiter->callback; 1972aedd662SScott Long free(waiter, M_DEVBUF); 1982aedd662SScott Long callback(command); 1992aedd662SScott Long return; 2002aedd662SScott Long } 2012aedd662SScott Long /* returns a free command struct if one is available. 2022aedd662SScott Long * It also blanks out anything that may be a wild pointer/value. 2032aedd662SScott Long * Also, command buffers are not freed. They are 2042aedd662SScott Long * small so they are saved and kept dmamapped and loaded. 2052aedd662SScott Long */ 2062aedd662SScott Long int ips_get_free_cmd(ips_softc_t *sc, int (*callback)(ips_command_t *), void *data, unsigned long flags) 2072aedd662SScott Long { 2082aedd662SScott Long intrmask_t mask; 2092aedd662SScott Long ips_command_t *command; 2102aedd662SScott Long mask = splbio(); 2112aedd662SScott Long 2122aedd662SScott Long if(sc->state & IPS_OFFLINE){ 2132aedd662SScott Long splx(mask); 2142aedd662SScott Long return EIO; 2152aedd662SScott Long } 2162aedd662SScott Long command = SLIST_FIRST(&sc->free_cmd_list); 2172aedd662SScott Long if(!command || (sc->state & IPS_TIMEOUT)){ 2182aedd662SScott Long splx(mask); 2192aedd662SScott Long if(flags & IPS_NOWAIT_FLAG) 2202aedd662SScott Long return EAGAIN; 2212aedd662SScott Long return ips_add_waiting_command(sc, callback, data, flags); 2222aedd662SScott Long } 2232aedd662SScott Long SLIST_REMOVE_HEAD(&sc->free_cmd_list, next); 2242aedd662SScott Long (sc->used_commands)++; 2252aedd662SScott Long splx(mask); 2262aedd662SScott Long clear_ips_command(command); 2272aedd662SScott Long bzero(command->command_buffer, IPS_COMMAND_LEN); 2282aedd662SScott Long command->arg = data; 2292aedd662SScott Long return callback(command); 2302aedd662SScott Long } 2312aedd662SScott Long 2322aedd662SScott Long /* adds a command back to the free command queue */ 2332aedd662SScott Long void ips_insert_free_cmd(ips_softc_t *sc, ips_command_t *command) 2342aedd662SScott Long { 2352aedd662SScott Long intrmask_t mask; 2362aedd662SScott Long mask = splbio(); 2372aedd662SScott Long SLIST_INSERT_HEAD(&sc->free_cmd_list, command, next); 2382aedd662SScott Long (sc->used_commands)--; 2392aedd662SScott Long splx(mask); 2402aedd662SScott Long if(!(sc->state & IPS_TIMEOUT)) 2412aedd662SScott Long ips_run_waiting_command(sc); 2422aedd662SScott Long } 2432aedd662SScott Long 2442aedd662SScott Long static int ips_diskdev_init(ips_softc_t *sc) 2452aedd662SScott Long { 2462aedd662SScott Long int i; 2472aedd662SScott Long for(i=0; i < IPS_MAX_NUM_DRIVES; i++){ 2482aedd662SScott Long if(sc->drives[i].state & IPS_LD_OKAY){ 2492aedd662SScott Long sc->diskdev[i] = device_add_child(sc->dev, NULL, -1); 250f472527cSPeter Wemm device_set_ivars(sc->diskdev[i],(void *)(uintptr_t) i); 2512aedd662SScott Long } 2522aedd662SScott Long } 2532aedd662SScott Long if(bus_generic_attach(sc->dev)){ 2542aedd662SScott Long device_printf(sc->dev, "Attaching bus failed\n"); 2552aedd662SScott Long } 2562aedd662SScott Long return 0; 2572aedd662SScott Long } 2582aedd662SScott Long 2592aedd662SScott Long static int ips_diskdev_free(ips_softc_t *sc) 2602aedd662SScott Long { 2612aedd662SScott Long int i; 2622aedd662SScott Long int error = 0; 2632aedd662SScott Long for(i = 0; i < IPS_MAX_NUM_DRIVES; i++){ 2642aedd662SScott Long if(sc->diskdev[i]) 2652aedd662SScott Long error = device_delete_child(sc->dev, sc->diskdev[i]); 2662aedd662SScott Long if(error) 2672aedd662SScott Long return error; 2682aedd662SScott Long } 2692aedd662SScott Long bus_generic_detach(sc->dev); 2702aedd662SScott Long return 0; 2712aedd662SScott Long } 2722aedd662SScott Long 2732aedd662SScott Long /* ips_timeout is periodically called to make sure no commands sent 2742aedd662SScott Long * to the card have become stuck. If it finds a stuck command, it 2752aedd662SScott Long * sets a flag so the driver won't start any more commands and then 2762aedd662SScott Long * is periodically called to see if all outstanding commands have 2772aedd662SScott Long * either finished or timed out. Once timed out, an attempt to 2782aedd662SScott Long * reinitialize the card is made. If that fails, the driver gives 2792aedd662SScott Long * up and declares the card dead. */ 2802aedd662SScott Long static void ips_timeout(void *arg) 2812aedd662SScott Long { 2822aedd662SScott Long intrmask_t mask; 2832aedd662SScott Long ips_softc_t *sc = arg; 2842aedd662SScott Long int i, state = 0; 2852aedd662SScott Long ips_command_t *command; 2862aedd662SScott Long command = &sc->commandarray[0]; 2872aedd662SScott Long mask = splbio(); 2882aedd662SScott Long for(i = 0; i < sc->max_cmds; i++){ 2892aedd662SScott Long if(!command[i].timeout){ 2902aedd662SScott Long continue; 2912aedd662SScott Long } 2922aedd662SScott Long command[i].timeout--; 2932aedd662SScott Long if(!command[i].timeout){ 2942aedd662SScott Long if(!(sc->state & IPS_TIMEOUT)){ 2952aedd662SScott Long sc->state |= IPS_TIMEOUT; 2962aedd662SScott Long device_printf(sc->dev, "WARNING: command timeout. Adapter is in toaster mode, resetting to known state\n"); 2972aedd662SScott Long } 2982aedd662SScott Long command[i].status.value = IPS_ERROR_STATUS; 2992aedd662SScott Long command[i].callback(&command[i]); 3002aedd662SScott Long /* hmm, this should be enough cleanup */ 3012aedd662SScott Long } else 3022aedd662SScott Long state = 1; 3032aedd662SScott Long } 3042aedd662SScott Long if(!state && (sc->state & IPS_TIMEOUT)){ 3052aedd662SScott Long if(sc->ips_adapter_reinit(sc, 1)){ 3062aedd662SScott Long device_printf(sc->dev, "AIEE! adapter reset failed, giving up and going home! Have a nice day.\n"); 3072aedd662SScott Long sc->state |= IPS_OFFLINE; 3082aedd662SScott Long sc->state &= ~IPS_TIMEOUT; 3092aedd662SScott Long /* Grr, I hate this solution. I run waiting commands 3102aedd662SScott Long one at a time and error them out just before they 3112aedd662SScott Long would go to the card. This sucks. */ 3122aedd662SScott Long } else 3132aedd662SScott Long sc->state &= ~IPS_TIMEOUT; 3142aedd662SScott Long ips_run_waiting_command(sc); 3152aedd662SScott Long } 3162aedd662SScott Long if (sc->state != IPS_OFFLINE) 3172aedd662SScott Long sc->timer = timeout(ips_timeout, sc, 10*hz); 3182aedd662SScott Long splx(mask); 3192aedd662SScott Long } 3202aedd662SScott Long 3212aedd662SScott Long /* check card and initialize it */ 3222aedd662SScott Long int ips_adapter_init(ips_softc_t *sc) 3232aedd662SScott Long { 324dea4622dSScott Long int i; 3252aedd662SScott Long DEVICE_PRINTF(1,sc->dev, "initializing\n"); 3262aedd662SScott Long if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 3272aedd662SScott Long /* alignemnt */ 1, 3282aedd662SScott Long /* boundary */ 0, 3292aedd662SScott Long /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 3302aedd662SScott Long /* highaddr */ BUS_SPACE_MAXADDR, 3312aedd662SScott Long /* filter */ NULL, 3322aedd662SScott Long /* filterarg */ NULL, 3332aedd662SScott Long /* maxsize */ IPS_COMMAND_LEN + 3342aedd662SScott Long IPS_MAX_SG_LEN, 3352aedd662SScott Long /* numsegs */ 1, 3362aedd662SScott Long /* maxsegsize*/ IPS_COMMAND_LEN + 3372aedd662SScott Long IPS_MAX_SG_LEN, 3382aedd662SScott Long /* flags */ 0, 339f6b1c44dSScott Long /* lockfunc */ busdma_lock_mutex, 340f6b1c44dSScott Long /* lockarg */ &Giant, 3412aedd662SScott Long &sc->command_dmatag) != 0) { 3422aedd662SScott Long device_printf(sc->dev, "can't alloc command dma tag\n"); 3432aedd662SScott Long goto error; 3442aedd662SScott Long } 3452aedd662SScott Long if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 3462aedd662SScott Long /* alignemnt */ 1, 3472aedd662SScott Long /* boundary */ 0, 3482aedd662SScott Long /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 3492aedd662SScott Long /* highaddr */ BUS_SPACE_MAXADDR, 3502aedd662SScott Long /* filter */ NULL, 3512aedd662SScott Long /* filterarg */ NULL, 3522aedd662SScott Long /* maxsize */ IPS_MAX_IOBUF_SIZE, 3532aedd662SScott Long /* numsegs */ IPS_MAX_SG_ELEMENTS, 3542aedd662SScott Long /* maxsegsize*/ IPS_MAX_IOBUF_SIZE, 3552aedd662SScott Long /* flags */ 0, 356f6b1c44dSScott Long /* lockfunc */ busdma_lock_mutex, 357f6b1c44dSScott Long /* lockarg */ &Giant, 3582aedd662SScott Long &sc->sg_dmatag) != 0) { 3592aedd662SScott Long device_printf(sc->dev, "can't alloc SG dma tag\n"); 3602aedd662SScott Long goto error; 3612aedd662SScott Long } 3622aedd662SScott Long /* create one command buffer until we know how many commands this card 3632aedd662SScott Long can handle */ 3642aedd662SScott Long sc->max_cmds = 1; 3652aedd662SScott Long ips_cmdqueue_init(sc); 366dea4622dSScott Long callout_handle_init(&sc->timer); 3672aedd662SScott Long 3682aedd662SScott Long if(sc->ips_adapter_reinit(sc, 0)) 3692aedd662SScott Long goto error; 3702aedd662SScott Long 3712aedd662SScott Long mtx_init(&sc->cmd_mtx, "ips command mutex", NULL, MTX_DEF); 372dea4622dSScott Long if ((i = ips_get_adapter_info(sc)) != 0) { 373dea4622dSScott Long device_printf(sc->dev, "failed to get adapter configuration data from device (%d)\n", i); 374dea4622dSScott Long goto error; 375dea4622dSScott Long } 376dea4622dSScott Long if ((i = ips_get_drive_info(sc)) != 0) { 377dea4622dSScott Long device_printf(sc->dev, "failed to get drive configuration data from device (%d)\n", i); 3782aedd662SScott Long goto error; 3792aedd662SScott Long } 3802aedd662SScott Long ips_update_nvram(sc); /* no error check as failure doesn't matter */ 3812aedd662SScott Long 3822aedd662SScott Long ips_cmdqueue_free(sc); 3832aedd662SScott Long if(sc->adapter_info.max_concurrent_cmds) 3842aedd662SScott Long sc->max_cmds = min(128, sc->adapter_info.max_concurrent_cmds); 3852aedd662SScott Long else 3862aedd662SScott Long sc->max_cmds = 32; 3872aedd662SScott Long if(ips_cmdqueue_init(sc)){ 3882aedd662SScott Long device_printf(sc->dev, "failed to initialize command buffers\n"); 3892aedd662SScott Long goto error; 3902aedd662SScott Long } 3912aedd662SScott Long sc->device_file = make_dev(&ips_cdevsw, device_get_unit(sc->dev), UID_ROOT, GID_OPERATOR, 3922aedd662SScott Long S_IRUSR | S_IWUSR, "ips%d", device_get_unit(sc->dev)); 3932aedd662SScott Long sc->device_file->si_drv1 = sc; 3942aedd662SScott Long ips_diskdev_init(sc); 3952aedd662SScott Long sc->timer = timeout(ips_timeout, sc, 10*hz); 3962aedd662SScott Long return 0; 3972aedd662SScott Long 3982aedd662SScott Long error: 3992aedd662SScott Long ips_adapter_free(sc); 4002aedd662SScott Long return ENXIO; 4012aedd662SScott Long } 4022aedd662SScott Long 4032aedd662SScott Long /* see if we should reinitialize the card and wait for it to timeout or complete initialization */ 4042aedd662SScott Long int ips_morpheus_reinit(ips_softc_t *sc, int force) 4052aedd662SScott Long { 4062aedd662SScott Long u_int32_t tmp; 4072aedd662SScott Long int i; 4082aedd662SScott Long 4092aedd662SScott Long tmp = ips_read_4(sc, MORPHEUS_REG_OISR); 4102aedd662SScott Long if(!force && (ips_read_4(sc, MORPHEUS_REG_OMR0) >= IPS_POST1_OK) && 4112aedd662SScott Long (ips_read_4(sc, MORPHEUS_REG_OMR1) != 0xdeadbeef) && !tmp){ 4122aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_OIMR, 0); 4132aedd662SScott Long return 0; 4142aedd662SScott Long } 4152aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_OIMR, 0xff); 4162aedd662SScott Long ips_read_4(sc, MORPHEUS_REG_OIMR); 4172aedd662SScott Long 4182aedd662SScott Long device_printf(sc->dev, "resetting adapter, this may take up to 5 minutes\n"); 4192aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_IDR, 0x80000000); 4202aedd662SScott Long DELAY(5000000); 4212aedd662SScott Long pci_read_config(sc->dev, 0, 4); 4222aedd662SScott Long 4232aedd662SScott Long tmp = ips_read_4(sc, MORPHEUS_REG_OISR); 4242aedd662SScott Long for(i = 0; i < 45 && !(tmp & MORPHEUS_BIT_POST1); i++){ 4252aedd662SScott Long DELAY(1000000); 4262aedd662SScott Long DEVICE_PRINTF(2, sc->dev, "post1: %d\n", i); 4272aedd662SScott Long tmp = ips_read_4(sc, MORPHEUS_REG_OISR); 4282aedd662SScott Long } 4292aedd662SScott Long if(tmp & MORPHEUS_BIT_POST1) 4302aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_OISR, MORPHEUS_BIT_POST1); 4312aedd662SScott Long 4322aedd662SScott Long if( i == 45 || ips_read_4(sc, MORPHEUS_REG_OMR0) < IPS_POST1_OK){ 4332aedd662SScott Long device_printf(sc->dev,"Adapter error during initialization.\n"); 4342aedd662SScott Long return 1; 4352aedd662SScott Long } 4362aedd662SScott Long for(i = 0; i < 240 && !(tmp & MORPHEUS_BIT_POST2); i++){ 4372aedd662SScott Long DELAY(1000000); 4382aedd662SScott Long DEVICE_PRINTF(2, sc->dev, "post2: %d\n", i); 4392aedd662SScott Long tmp = ips_read_4(sc, MORPHEUS_REG_OISR); 4402aedd662SScott Long } 4412aedd662SScott Long if(tmp & MORPHEUS_BIT_POST2) 4422aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_OISR, MORPHEUS_BIT_POST2); 4432aedd662SScott Long 4442aedd662SScott Long if(i == 240 || !ips_read_4(sc, MORPHEUS_REG_OMR1)){ 4452aedd662SScott Long device_printf(sc->dev, "adapter failed config check\n"); 4462aedd662SScott Long return 1; 4472aedd662SScott Long } 4482aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_OIMR, 0); 4492aedd662SScott Long if(force && ips_clear_adapter(sc)){ 4502aedd662SScott Long device_printf(sc->dev, "adapter clear failed\n"); 4512aedd662SScott Long return 1; 4522aedd662SScott Long } 4532aedd662SScott Long return 0; 4542aedd662SScott Long } 4552aedd662SScott Long 4562aedd662SScott Long /* clean up so we can unload the driver. */ 4572aedd662SScott Long int ips_adapter_free(ips_softc_t *sc) 4582aedd662SScott Long { 4592aedd662SScott Long int error = 0; 4602aedd662SScott Long intrmask_t mask; 4612aedd662SScott Long if(sc->state & IPS_DEV_OPEN) 4622aedd662SScott Long return EBUSY; 4632aedd662SScott Long if((error = ips_diskdev_free(sc))) 4642aedd662SScott Long return error; 4652aedd662SScott Long if(ips_cmdqueue_free(sc)){ 4662aedd662SScott Long device_printf(sc->dev, 4672aedd662SScott Long "trying to exit when command queue is not empty!\n"); 4682aedd662SScott Long return EBUSY; 4692aedd662SScott Long } 4702aedd662SScott Long DEVICE_PRINTF(1, sc->dev, "free\n"); 4712aedd662SScott Long mask = splbio(); 4722aedd662SScott Long untimeout(ips_timeout, sc, sc->timer); 4732aedd662SScott Long splx(mask); 4742aedd662SScott Long if (mtx_initialized(&sc->cmd_mtx)) 4752aedd662SScott Long mtx_destroy(&sc->cmd_mtx); 4762aedd662SScott Long 4772aedd662SScott Long if(sc->sg_dmatag) 4782aedd662SScott Long bus_dma_tag_destroy(sc->sg_dmatag); 4792aedd662SScott Long if(sc->command_dmatag) 4802aedd662SScott Long bus_dma_tag_destroy(sc->command_dmatag); 4812aedd662SScott Long if(sc->device_file) 4822aedd662SScott Long destroy_dev(sc->device_file); 4832aedd662SScott Long return 0; 4842aedd662SScott Long } 4852aedd662SScott Long 4862aedd662SScott Long void ips_morpheus_intr(void *void_sc) 4872aedd662SScott Long { 4882aedd662SScott Long ips_softc_t *sc = (ips_softc_t *)void_sc; 4892aedd662SScott Long u_int32_t oisr, iisr; 4902aedd662SScott Long int cmdnumber; 4912aedd662SScott Long ips_cmd_status_t status; 4922aedd662SScott Long 4932aedd662SScott Long iisr =ips_read_4(sc, MORPHEUS_REG_IISR); 4942aedd662SScott Long oisr =ips_read_4(sc, MORPHEUS_REG_OISR); 4952aedd662SScott Long PRINTF(9,"interrupt registers in:%x out:%x\n",iisr, oisr); 4962aedd662SScott Long if(!(oisr & MORPHEUS_BIT_CMD_IRQ)){ 4972aedd662SScott Long DEVICE_PRINTF(2,sc->dev, "got a non-command irq\n"); 4982aedd662SScott Long return; 4992aedd662SScott Long } 5002aedd662SScott Long while((status.value = ips_read_4(sc, MORPHEUS_REG_OQPR)) != 0xffffffff){ 5012aedd662SScott Long cmdnumber = status.fields.command_id; 5022aedd662SScott Long sc->commandarray[cmdnumber].status.value = status.value; 5032aedd662SScott Long sc->commandarray[cmdnumber].timeout = 0; 5042aedd662SScott Long sc->commandarray[cmdnumber].callback(&(sc->commandarray[cmdnumber])); 5052aedd662SScott Long 5062aedd662SScott Long 5072aedd662SScott Long DEVICE_PRINTF(9,sc->dev, "got command %d\n", cmdnumber); 5082aedd662SScott Long } 5092aedd662SScott Long return; 5102aedd662SScott Long } 5112aedd662SScott Long 5122aedd662SScott Long void ips_issue_morpheus_cmd(ips_command_t *command) 5132aedd662SScott Long { 5142aedd662SScott Long intrmask_t mask = splbio(); 5152aedd662SScott Long /* hmmm, is there a cleaner way to do this? */ 5162aedd662SScott Long if(command->sc->state & IPS_OFFLINE){ 5172aedd662SScott Long splx(mask); 5182aedd662SScott Long command->status.value = IPS_ERROR_STATUS; 5192aedd662SScott Long command->callback(command); 5202aedd662SScott Long return; 5212aedd662SScott Long } 5222aedd662SScott Long command->timeout = 10; 5232aedd662SScott Long ips_write_4(command->sc, MORPHEUS_REG_IQPR, command->command_phys_addr); 5242aedd662SScott Long splx(mask); 5252aedd662SScott Long } 5262aedd662SScott Long 5272aedd662SScott Long static void ips_copperhead_queue_callback(void *queueptr, bus_dma_segment_t *segments,int segnum, int error) 5282aedd662SScott Long { 5292aedd662SScott Long ips_copper_queue_t *queue = queueptr; 5302aedd662SScott Long if(error){ 5312aedd662SScott Long return; 5322aedd662SScott Long } 5332aedd662SScott Long queue->base_phys_addr = segments[0].ds_addr; 5342aedd662SScott Long } 5352aedd662SScott Long 5362aedd662SScott Long static int ips_copperhead_queue_init(ips_softc_t *sc) 5372aedd662SScott Long { 5382aedd662SScott Long int error; 5392aedd662SScott Long bus_dma_tag_t dmatag; 5402aedd662SScott Long bus_dmamap_t dmamap; 5412aedd662SScott Long if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 5422aedd662SScott Long /* alignemnt */ 1, 5432aedd662SScott Long /* boundary */ 0, 5442aedd662SScott Long /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 5452aedd662SScott Long /* highaddr */ BUS_SPACE_MAXADDR, 5462aedd662SScott Long /* filter */ NULL, 5472aedd662SScott Long /* filterarg */ NULL, 5482aedd662SScott Long /* maxsize */ sizeof(ips_copper_queue_t), 5492aedd662SScott Long /* numsegs */ 1, 5502aedd662SScott Long /* maxsegsize*/ sizeof(ips_copper_queue_t), 5512aedd662SScott Long /* flags */ 0, 552f6b1c44dSScott Long /* lockfunc */ busdma_lock_mutex, 553f6b1c44dSScott Long /* lockarg */ &Giant, 5542aedd662SScott Long &dmatag) != 0) { 5552aedd662SScott Long device_printf(sc->dev, "can't alloc dma tag for statue queue\n"); 5562aedd662SScott Long error = ENOMEM; 5572aedd662SScott Long goto exit; 5582aedd662SScott Long } 5592aedd662SScott Long if(bus_dmamem_alloc(dmatag, (void *)&(sc->copper_queue), 5602aedd662SScott Long BUS_DMA_NOWAIT, &dmamap)){ 5612aedd662SScott Long error = ENOMEM; 5622aedd662SScott Long goto exit; 5632aedd662SScott Long } 5642aedd662SScott Long bzero(sc->copper_queue, sizeof(ips_copper_queue_t)); 5652aedd662SScott Long sc->copper_queue->dmatag = dmatag; 5662aedd662SScott Long sc->copper_queue->dmamap = dmamap; 5672aedd662SScott Long sc->copper_queue->nextstatus = 1; 5682aedd662SScott Long bus_dmamap_load(dmatag, dmamap, 5692aedd662SScott Long &(sc->copper_queue->status[0]), IPS_MAX_CMD_NUM * 4, 5702aedd662SScott Long ips_copperhead_queue_callback, sc->copper_queue, 5712aedd662SScott Long BUS_DMA_NOWAIT); 5722aedd662SScott Long if(sc->copper_queue->base_phys_addr == 0){ 5732aedd662SScott Long error = ENOMEM; 5742aedd662SScott Long goto exit; 5752aedd662SScott Long } 5762aedd662SScott Long ips_write_4(sc, COPPER_REG_SQSR, sc->copper_queue->base_phys_addr); 5772aedd662SScott Long ips_write_4(sc, COPPER_REG_SQER, sc->copper_queue->base_phys_addr + 5782aedd662SScott Long IPS_MAX_CMD_NUM * 4); 5792aedd662SScott Long ips_write_4(sc, COPPER_REG_SQHR, sc->copper_queue->base_phys_addr + 4); 5802aedd662SScott Long ips_write_4(sc, COPPER_REG_SQTR, sc->copper_queue->base_phys_addr); 5812aedd662SScott Long 5822aedd662SScott Long 5832aedd662SScott Long return 0; 5842aedd662SScott Long exit: 5852aedd662SScott Long bus_dmamem_free(dmatag, sc->copper_queue, dmamap); 5862aedd662SScott Long bus_dma_tag_destroy(dmatag); 5872aedd662SScott Long return error; 5882aedd662SScott Long } 5892aedd662SScott Long 5902aedd662SScott Long /* see if we should reinitialize the card and wait for it to timeout or complete initialization FIXME */ 5912aedd662SScott Long int ips_copperhead_reinit(ips_softc_t *sc, int force) 5922aedd662SScott Long { 5932aedd662SScott Long int i, j; 5942aedd662SScott Long u_int32_t postcode = 0, configstatus = 0; 5952aedd662SScott Long ips_write_1(sc, COPPER_REG_SCPR, 0x80); 5962aedd662SScott Long ips_write_1(sc, COPPER_REG_SCPR, 0); 5972aedd662SScott Long device_printf(sc->dev, "reinitializing adapter, this could take several minutes.\n"); 5982aedd662SScott Long for(j = 0; j < 2; j++){ 5992aedd662SScott Long postcode <<= 8; 6002aedd662SScott Long for(i = 0; i < 45; i++){ 6012aedd662SScott Long if(ips_read_1(sc, COPPER_REG_HISR) & COPPER_GHI_BIT){ 6022aedd662SScott Long postcode |= ips_read_1(sc, COPPER_REG_ISPR); 6032aedd662SScott Long ips_write_1(sc, COPPER_REG_HISR, 6042aedd662SScott Long COPPER_GHI_BIT); 6052aedd662SScott Long break; 6062aedd662SScott Long } else 6072aedd662SScott Long DELAY(1000000); 6082aedd662SScott Long } 6092aedd662SScott Long if(i == 45) 6102aedd662SScott Long return 1; 6112aedd662SScott Long } 6122aedd662SScott Long for(j = 0; j < 2; j++){ 6132aedd662SScott Long configstatus <<= 8; 6142aedd662SScott Long for(i = 0; i < 240; i++){ 6152aedd662SScott Long if(ips_read_1(sc, COPPER_REG_HISR) & COPPER_GHI_BIT){ 6162aedd662SScott Long configstatus |= ips_read_1(sc, COPPER_REG_ISPR); 6172aedd662SScott Long ips_write_1(sc, COPPER_REG_HISR, 6182aedd662SScott Long COPPER_GHI_BIT); 6192aedd662SScott Long break; 6202aedd662SScott Long } else 6212aedd662SScott Long DELAY(1000000); 6222aedd662SScott Long } 6232aedd662SScott Long if(i == 240) 6242aedd662SScott Long return 1; 6252aedd662SScott Long } 6262aedd662SScott Long for(i = 0; i < 240; i++){ 6272aedd662SScott Long if(!(ips_read_1(sc, COPPER_REG_CBSP) & COPPER_OP_BIT)){ 6282aedd662SScott Long break; 6292aedd662SScott Long } else 6302aedd662SScott Long DELAY(1000000); 6312aedd662SScott Long } 6322aedd662SScott Long if(i == 240) 6332aedd662SScott Long return 1; 6342aedd662SScott Long ips_write_2(sc, COPPER_REG_CCCR, 0x1000 | COPPER_ILE_BIT); 6352aedd662SScott Long ips_write_1(sc, COPPER_REG_SCPR, COPPER_EBM_BIT); 6362aedd662SScott Long ips_copperhead_queue_init(sc); 6372aedd662SScott Long ips_write_1(sc, COPPER_REG_HISR, COPPER_GHI_BIT); 6382aedd662SScott Long i = ips_read_1(sc, COPPER_REG_SCPR); 6392aedd662SScott Long ips_write_1(sc, COPPER_REG_HISR, COPPER_EI_BIT); 6402aedd662SScott Long if(!configstatus){ 6412aedd662SScott Long device_printf(sc->dev, "adapter initialization failed\n"); 6422aedd662SScott Long return 1; 6432aedd662SScott Long } 6442aedd662SScott Long if(force && ips_clear_adapter(sc)){ 6452aedd662SScott Long device_printf(sc->dev, "adapter clear failed\n"); 6462aedd662SScott Long return 1; 6472aedd662SScott Long } 6482aedd662SScott Long return 0; 6492aedd662SScott Long } 6502aedd662SScott Long static u_int32_t ips_copperhead_cmd_status(ips_softc_t *sc) 6512aedd662SScott Long { 6522aedd662SScott Long intrmask_t mask; 6532aedd662SScott Long u_int32_t value; 6542aedd662SScott Long int statnum = sc->copper_queue->nextstatus++; 6552aedd662SScott Long if(sc->copper_queue->nextstatus == IPS_MAX_CMD_NUM) 6562aedd662SScott Long sc->copper_queue->nextstatus = 0; 6572aedd662SScott Long mask = splbio(); 6582aedd662SScott Long value = sc->copper_queue->status[statnum]; 6592aedd662SScott Long ips_write_4(sc, COPPER_REG_SQTR, sc->copper_queue->base_phys_addr + 6602aedd662SScott Long 4 * statnum); 6612aedd662SScott Long splx(mask); 6622aedd662SScott Long return value; 6632aedd662SScott Long } 6642aedd662SScott Long 6652aedd662SScott Long 6662aedd662SScott Long void ips_copperhead_intr(void *void_sc) 6672aedd662SScott Long { 6682aedd662SScott Long ips_softc_t *sc = (ips_softc_t *)void_sc; 6692aedd662SScott Long int cmdnumber; 6702aedd662SScott Long ips_cmd_status_t status; 6712aedd662SScott Long 6722aedd662SScott Long while(ips_read_1(sc, COPPER_REG_HISR) & COPPER_SCE_BIT){ 6732aedd662SScott Long status.value = ips_copperhead_cmd_status(sc); 6742aedd662SScott Long cmdnumber = status.fields.command_id; 6752aedd662SScott Long sc->commandarray[cmdnumber].status.value = status.value; 6762aedd662SScott Long sc->commandarray[cmdnumber].timeout = 0; 6772aedd662SScott Long sc->commandarray[cmdnumber].callback(&(sc->commandarray[cmdnumber])); 6782aedd662SScott Long PRINTF(9, "ips: got command %d\n", cmdnumber); 6792aedd662SScott Long } 6802aedd662SScott Long return; 6812aedd662SScott Long } 6822aedd662SScott Long 6832aedd662SScott Long void ips_issue_copperhead_cmd(ips_command_t *command) 6842aedd662SScott Long { 6852aedd662SScott Long int i; 6862aedd662SScott Long intrmask_t mask = splbio(); 6872aedd662SScott Long /* hmmm, is there a cleaner way to do this? */ 6882aedd662SScott Long if(command->sc->state & IPS_OFFLINE){ 6892aedd662SScott Long splx(mask); 6902aedd662SScott Long command->status.value = IPS_ERROR_STATUS; 6912aedd662SScott Long command->callback(command); 6922aedd662SScott Long return; 6932aedd662SScott Long } 6942aedd662SScott Long command->timeout = 10; 6952aedd662SScott Long for(i = 0; ips_read_4(command->sc, COPPER_REG_CCCR) & COPPER_SEM_BIT; 6962aedd662SScott Long i++ ){ 6972aedd662SScott Long if( i == 20){ 6982aedd662SScott Long printf("sem bit still set, can't send a command\n"); 6992aedd662SScott Long splx(mask); 7002aedd662SScott Long return; 7012aedd662SScott Long } 7022aedd662SScott Long DELAY(500);/* need to do a delay here */ 7032aedd662SScott Long } 7042aedd662SScott Long ips_write_4(command->sc, COPPER_REG_CCSAR, command->command_phys_addr); 7052aedd662SScott Long ips_write_2(command->sc, COPPER_REG_CCCR, COPPER_CMD_START); 7062aedd662SScott Long splx(mask); 7072aedd662SScott Long } 7082aedd662SScott Long 709