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