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 40dd83a01eSScott Long MALLOC_DEFINE(M_IPSBUF, "ipsbuf","IPS driver buffer"); 41dd83a01eSScott Long 422aedd662SScott Long static struct cdevsw ips_cdevsw = { 43dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 44dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 452aedd662SScott Long .d_open = ips_open, 462aedd662SScott Long .d_close = ips_close, 472aedd662SScott Long .d_ioctl = ips_ioctl, 482aedd662SScott Long .d_name = "ips", 492aedd662SScott Long }; 502aedd662SScott Long 517633e7f1SMartin Blapp static const char* ips_adapter_name[] = { 527633e7f1SMartin Blapp "N/A", 537633e7f1SMartin Blapp "ServeRAID (copperhead)", 547633e7f1SMartin Blapp "ServeRAID II (copperhead refresh)", 557633e7f1SMartin Blapp "ServeRAID onboard (copperhead)", 567633e7f1SMartin Blapp "ServeRAID onboard (copperhead)", 577633e7f1SMartin Blapp "ServeRAID 3H (clarinet)", 587633e7f1SMartin Blapp "ServeRAID 3L (clarinet lite)", 597633e7f1SMartin Blapp "ServeRAID 4H (trombone)", 607633e7f1SMartin Blapp "ServeRAID 4M (morpheus)", 617633e7f1SMartin Blapp "ServeRAID 4L (morpheus lite)", 627633e7f1SMartin Blapp "ServeRAID 4Mx (neo)", 637633e7f1SMartin Blapp "ServeRAID 4Lx (neo lite)", 647633e7f1SMartin Blapp "ServeRAID 5i II (sarasota)", 657633e7f1SMartin Blapp "ServeRAID 5i (sarasota)", 667633e7f1SMartin Blapp "ServeRAID 6M (marco)", 677633e7f1SMartin Blapp "ServeRAID 6i (sebring)" 687633e7f1SMartin Blapp }; 697633e7f1SMartin Blapp 702aedd662SScott Long 7189c9c53dSPoul-Henning Kamp static int ips_open(struct cdev *dev, int flags, int fmt, struct thread *td) 722aedd662SScott Long { 732aedd662SScott Long ips_softc_t *sc = dev->si_drv1; 742aedd662SScott Long sc->state |= IPS_DEV_OPEN; 752aedd662SScott Long return 0; 762aedd662SScott Long } 772aedd662SScott Long 7889c9c53dSPoul-Henning Kamp static int ips_close(struct cdev *dev, int flags, int fmt, struct thread *td) 792aedd662SScott Long { 802aedd662SScott Long ips_softc_t *sc = dev->si_drv1; 812aedd662SScott Long sc->state &= ~IPS_DEV_OPEN; 822aedd662SScott Long 832aedd662SScott Long return 0; 842aedd662SScott Long } 852aedd662SScott Long 8689c9c53dSPoul-Henning Kamp static int ips_ioctl(struct cdev *dev, u_long command, caddr_t addr, int32_t flags, struct thread *td) 872aedd662SScott Long { 882aedd662SScott Long ips_softc_t *sc; 892aedd662SScott Long 902aedd662SScott Long sc = dev->si_drv1; 912aedd662SScott Long return ips_ioctl_request(sc, command, addr, flags); 922aedd662SScott Long } 932aedd662SScott Long 942aedd662SScott Long static void ips_cmd_dmaload(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) 952aedd662SScott Long { 962aedd662SScott Long ips_command_t *command = cmdptr; 972aedd662SScott Long PRINTF(10, "ips: in ips_cmd_dmaload\n"); 982aedd662SScott Long if(!error) 992aedd662SScott Long command->command_phys_addr = segments[0].ds_addr; 1002aedd662SScott Long 1012aedd662SScott Long } 1022aedd662SScott Long 1032aedd662SScott Long /* is locking needed? what locking guarentees are there on removal? */ 10403a908f2SScott Long static int ips_cmdqueue_free(ips_softc_t *sc) 1052aedd662SScott Long { 1062aedd662SScott Long int i, error = -1; 107b234a120SScott Long ips_command_t *command; 108b234a120SScott Long 1092aedd662SScott Long if(!sc->used_commands){ 1102aedd662SScott Long for(i = 0; i < sc->max_cmds; i++){ 111b234a120SScott Long 112b234a120SScott Long command = &sc->commandarray[i]; 113b234a120SScott Long 114b234a120SScott Long if(command->command_phys_addr == 0) 1152aedd662SScott Long continue; 1162aedd662SScott Long bus_dmamap_unload(sc->command_dmatag, 117b234a120SScott Long command->command_dmamap); 1182aedd662SScott Long bus_dmamem_free(sc->command_dmatag, 119b234a120SScott Long command->command_buffer, 120b234a120SScott Long command->command_dmamap); 12103a908f2SScott Long if (command->data_dmamap != NULL) 12203a908f2SScott Long bus_dmamap_destroy(command->data_dmatag, 12303a908f2SScott Long command->data_dmamap); 1242aedd662SScott Long } 1252aedd662SScott Long error = 0; 1262aedd662SScott Long sc->state |= IPS_OFFLINE; 1272aedd662SScott Long } 12803a908f2SScott Long sc->staticcmd = NULL; 12903a908f2SScott Long free(sc->commandarray, M_DEVBUF); 1302aedd662SScott Long return error; 1312aedd662SScott Long } 1322aedd662SScott Long 1332aedd662SScott Long /* places all ips command structs on the free command queue. No locking as if someone else tries 1342aedd662SScott Long * to access this during init, we have bigger problems */ 13503a908f2SScott Long static int ips_cmdqueue_init(ips_softc_t *sc) 1362aedd662SScott Long { 1372aedd662SScott Long int i; 1382aedd662SScott Long ips_command_t *command; 13903a908f2SScott Long 14003a908f2SScott Long sc->commandarray = (ips_command_t *)malloc(sizeof(ips_command_t) * 14103a908f2SScott Long sc->max_cmds, M_DEVBUF, M_NOWAIT|M_ZERO); 14203a908f2SScott Long if (sc->commandarray == NULL) 14303a908f2SScott Long return (ENOMEM); 14403a908f2SScott Long 1452aedd662SScott Long SLIST_INIT(&sc->free_cmd_list); 1462aedd662SScott Long for(i = 0; i < sc->max_cmds; i++){ 1472aedd662SScott Long command = &sc->commandarray[i]; 148b234a120SScott Long command->id = i; 149b234a120SScott Long command->sc = sc; 150b234a120SScott Long 1512aedd662SScott Long if(bus_dmamem_alloc(sc->command_dmatag,&command->command_buffer, 1522aedd662SScott Long BUS_DMA_NOWAIT, &command->command_dmamap)) 1532aedd662SScott Long goto error; 1542aedd662SScott Long bus_dmamap_load(sc->command_dmatag, command->command_dmamap, 1552aedd662SScott Long command->command_buffer,IPS_COMMAND_LEN, 1562aedd662SScott Long ips_cmd_dmaload, command, BUS_DMA_NOWAIT); 1572aedd662SScott Long if(!command->command_phys_addr){ 1582aedd662SScott Long bus_dmamem_free(sc->command_dmatag, 1592aedd662SScott Long command->command_buffer, command->command_dmamap); 1602aedd662SScott Long goto error; 1612aedd662SScott Long } 162b234a120SScott Long 16303a908f2SScott Long if (i != 0) { 16403a908f2SScott Long command->data_dmatag = sc->sg_dmatag; 16503a908f2SScott Long if (bus_dmamap_create(command->data_dmatag, 0, 16603a908f2SScott Long &command->data_dmamap)) 16703a908f2SScott Long goto error; 168b234a120SScott Long SLIST_INSERT_HEAD(&sc->free_cmd_list, command, next); 16903a908f2SScott Long } else 17003a908f2SScott Long sc->staticcmd = command; 1712aedd662SScott Long } 1722aedd662SScott Long sc->state &= ~IPS_OFFLINE; 1732aedd662SScott Long return 0; 1742aedd662SScott Long error: 1752aedd662SScott Long ips_cmdqueue_free(sc); 1762aedd662SScott Long return ENOMEM; 1772aedd662SScott Long } 1782aedd662SScott Long 1792aedd662SScott Long /* returns a free command struct if one is available. 1802aedd662SScott Long * It also blanks out anything that may be a wild pointer/value. 1812aedd662SScott Long * Also, command buffers are not freed. They are 1822aedd662SScott Long * small so they are saved and kept dmamapped and loaded. 1832aedd662SScott Long */ 18403a908f2SScott Long int ips_get_free_cmd(ips_softc_t *sc, ips_command_t **cmd, unsigned long flags) 1852aedd662SScott Long { 1862aedd662SScott Long ips_command_t *command; 1872aedd662SScott Long 1882aedd662SScott Long if(sc->state & IPS_OFFLINE){ 1892aedd662SScott Long return EIO; 1902aedd662SScott Long } 19103a908f2SScott Long if ((flags & IPS_STATIC_FLAG) == 0) { 1922aedd662SScott Long command = SLIST_FIRST(&sc->free_cmd_list); 1932aedd662SScott Long if(!command || (sc->state & IPS_TIMEOUT)){ 19403a908f2SScott Long return EBUSY; 1952aedd662SScott Long } 1962aedd662SScott Long SLIST_REMOVE_HEAD(&sc->free_cmd_list, next); 1972aedd662SScott Long (sc->used_commands)++; 19803a908f2SScott Long } else { 19903a908f2SScott Long if (sc->state & IPS_STATIC_BUSY) 20003a908f2SScott Long return EAGAIN; 20103a908f2SScott Long command = sc->staticcmd; 20203a908f2SScott Long sc->state |= IPS_STATIC_BUSY; 20303a908f2SScott Long } 2042aedd662SScott Long clear_ips_command(command); 2052aedd662SScott Long bzero(command->command_buffer, IPS_COMMAND_LEN); 20603a908f2SScott Long *cmd = command; 20703a908f2SScott Long return 0; 2082aedd662SScott Long } 2092aedd662SScott Long 2102aedd662SScott Long /* adds a command back to the free command queue */ 2112aedd662SScott Long void ips_insert_free_cmd(ips_softc_t *sc, ips_command_t *command) 2122aedd662SScott Long { 213b234a120SScott Long 21403a908f2SScott Long if (sema_value(&sc->cmd_sema) != 0) 215b234a120SScott Long panic("ips: command returned non-zero semaphore"); 216b234a120SScott Long 21703a908f2SScott Long if (command != sc->staticcmd) { 2182aedd662SScott Long SLIST_INSERT_HEAD(&sc->free_cmd_list, command, next); 2192aedd662SScott Long (sc->used_commands)--; 22003a908f2SScott Long } else { 22103a908f2SScott Long sc->state &= ~IPS_STATIC_BUSY; 22203a908f2SScott Long } 2232aedd662SScott Long } 2247633e7f1SMartin Blapp static const char* ips_diskdev_statename(u_int8_t state) 2257633e7f1SMartin Blapp { 2267633e7f1SMartin Blapp static char statebuf[20]; 2277633e7f1SMartin Blapp switch(state){ 2287633e7f1SMartin Blapp case IPS_LD_OFFLINE: 2297633e7f1SMartin Blapp return("OFFLINE"); 2307633e7f1SMartin Blapp break; 2317633e7f1SMartin Blapp case IPS_LD_OKAY: 2327633e7f1SMartin Blapp return("OK"); 2337633e7f1SMartin Blapp break; 2347633e7f1SMartin Blapp case IPS_LD_DEGRADED: 2357633e7f1SMartin Blapp return("DEGRADED"); 2367633e7f1SMartin Blapp break; 2377633e7f1SMartin Blapp case IPS_LD_FREE: 2387633e7f1SMartin Blapp return("FREE"); 2397633e7f1SMartin Blapp break; 2407633e7f1SMartin Blapp case IPS_LD_SYS: 2417633e7f1SMartin Blapp return("SYS"); 2427633e7f1SMartin Blapp break; 2437633e7f1SMartin Blapp case IPS_LD_CRS: 2447633e7f1SMartin Blapp return("CRS"); 2457633e7f1SMartin Blapp break; 2467633e7f1SMartin Blapp } 2477633e7f1SMartin Blapp sprintf(statebuf,"UNKNOWN(0x%02x)", state); 2487633e7f1SMartin Blapp return(statebuf); 2497633e7f1SMartin Blapp } 2502aedd662SScott Long 2512aedd662SScott Long static int ips_diskdev_init(ips_softc_t *sc) 2522aedd662SScott Long { 2532aedd662SScott Long int i; 2542aedd662SScott Long for(i=0; i < IPS_MAX_NUM_DRIVES; i++){ 2557633e7f1SMartin Blapp if(sc->drives[i].state == IPS_LD_FREE) continue; 2567633e7f1SMartin Blapp device_printf(sc->dev, "Logical Drive %d: RAID%d sectors: %u, state %s\n", 2577633e7f1SMartin Blapp i, sc->drives[i].raid_lvl, 2587633e7f1SMartin Blapp sc->drives[i].sector_count, 2597633e7f1SMartin Blapp ips_diskdev_statename(sc->drives[i].state)); 2607633e7f1SMartin Blapp if(sc->drives[i].state == IPS_LD_OKAY || 2617633e7f1SMartin Blapp sc->drives[i].state == IPS_LD_DEGRADED){ 2622aedd662SScott Long sc->diskdev[i] = device_add_child(sc->dev, NULL, -1); 263f472527cSPeter Wemm device_set_ivars(sc->diskdev[i],(void *)(uintptr_t) i); 2642aedd662SScott Long } 2652aedd662SScott Long } 2662aedd662SScott Long if(bus_generic_attach(sc->dev)){ 2672aedd662SScott Long device_printf(sc->dev, "Attaching bus failed\n"); 2682aedd662SScott Long } 2692aedd662SScott Long return 0; 2702aedd662SScott Long } 2712aedd662SScott Long 2722aedd662SScott Long static int ips_diskdev_free(ips_softc_t *sc) 2732aedd662SScott Long { 2742aedd662SScott Long int i; 2752aedd662SScott Long int error = 0; 2762aedd662SScott Long for(i = 0; i < IPS_MAX_NUM_DRIVES; i++){ 2772aedd662SScott Long if(sc->diskdev[i]) 2782aedd662SScott Long error = device_delete_child(sc->dev, sc->diskdev[i]); 2792aedd662SScott Long if(error) 2802aedd662SScott Long return error; 2812aedd662SScott Long } 2822aedd662SScott Long bus_generic_detach(sc->dev); 2832aedd662SScott Long return 0; 2842aedd662SScott Long } 2852aedd662SScott Long 2862aedd662SScott Long /* ips_timeout is periodically called to make sure no commands sent 2872aedd662SScott Long * to the card have become stuck. If it finds a stuck command, it 2882aedd662SScott Long * sets a flag so the driver won't start any more commands and then 2892aedd662SScott Long * is periodically called to see if all outstanding commands have 2902aedd662SScott Long * either finished or timed out. Once timed out, an attempt to 2912aedd662SScott Long * reinitialize the card is made. If that fails, the driver gives 2922aedd662SScott Long * up and declares the card dead. */ 2932aedd662SScott Long static void ips_timeout(void *arg) 2942aedd662SScott Long { 2952aedd662SScott Long ips_softc_t *sc = arg; 2962aedd662SScott Long int i, state = 0; 2972aedd662SScott Long ips_command_t *command; 29803a908f2SScott Long 29903a908f2SScott Long mtx_lock(&sc->queue_mtx); 3002aedd662SScott Long command = &sc->commandarray[0]; 3012aedd662SScott Long for(i = 0; i < sc->max_cmds; i++){ 3022aedd662SScott Long if(!command[i].timeout){ 3032aedd662SScott Long continue; 3042aedd662SScott Long } 3052aedd662SScott Long command[i].timeout--; 3062aedd662SScott Long if(!command[i].timeout){ 3072aedd662SScott Long if(!(sc->state & IPS_TIMEOUT)){ 3082aedd662SScott Long sc->state |= IPS_TIMEOUT; 3092aedd662SScott Long device_printf(sc->dev, "WARNING: command timeout. Adapter is in toaster mode, resetting to known state\n"); 3102aedd662SScott Long } 3112aedd662SScott Long command[i].status.value = IPS_ERROR_STATUS; 3122aedd662SScott Long command[i].callback(&command[i]); 3132aedd662SScott Long /* hmm, this should be enough cleanup */ 3142aedd662SScott Long } else 3152aedd662SScott Long state = 1; 3162aedd662SScott Long } 3172aedd662SScott Long if(!state && (sc->state & IPS_TIMEOUT)){ 3182aedd662SScott Long if(sc->ips_adapter_reinit(sc, 1)){ 3192aedd662SScott Long device_printf(sc->dev, "AIEE! adapter reset failed, giving up and going home! Have a nice day.\n"); 3202aedd662SScott Long sc->state |= IPS_OFFLINE; 3212aedd662SScott Long sc->state &= ~IPS_TIMEOUT; 3222aedd662SScott Long /* Grr, I hate this solution. I run waiting commands 3232aedd662SScott Long one at a time and error them out just before they 3242aedd662SScott Long would go to the card. This sucks. */ 3252aedd662SScott Long } else 3262aedd662SScott Long sc->state &= ~IPS_TIMEOUT; 3272aedd662SScott Long } 3282aedd662SScott Long if (sc->state != IPS_OFFLINE) 3292aedd662SScott Long sc->timer = timeout(ips_timeout, sc, 10*hz); 33003a908f2SScott Long mtx_unlock(&sc->queue_mtx); 3312aedd662SScott Long } 3322aedd662SScott Long 3332aedd662SScott Long /* check card and initialize it */ 3342aedd662SScott Long int ips_adapter_init(ips_softc_t *sc) 3352aedd662SScott Long { 336dea4622dSScott Long int i; 3372aedd662SScott Long DEVICE_PRINTF(1,sc->dev, "initializing\n"); 338b234a120SScott Long 3392aedd662SScott Long if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 3402aedd662SScott Long /* alignemnt */ 1, 3412aedd662SScott Long /* boundary */ 0, 3422aedd662SScott Long /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 3432aedd662SScott Long /* highaddr */ BUS_SPACE_MAXADDR, 3442aedd662SScott Long /* filter */ NULL, 3452aedd662SScott Long /* filterarg */ NULL, 3462aedd662SScott Long /* maxsize */ IPS_COMMAND_LEN + 3472aedd662SScott Long IPS_MAX_SG_LEN, 3482aedd662SScott Long /* numsegs */ 1, 3492aedd662SScott Long /* maxsegsize*/ IPS_COMMAND_LEN + 3502aedd662SScott Long IPS_MAX_SG_LEN, 3512aedd662SScott Long /* flags */ 0, 35203a908f2SScott Long /* lockfunc */ NULL, 35303a908f2SScott Long /* lockarg */ NULL, 3542aedd662SScott Long &sc->command_dmatag) != 0) { 3552aedd662SScott Long device_printf(sc->dev, "can't alloc command dma tag\n"); 3562aedd662SScott Long goto error; 3572aedd662SScott Long } 3582aedd662SScott Long if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 3592aedd662SScott Long /* alignemnt */ 1, 3602aedd662SScott Long /* boundary */ 0, 3612aedd662SScott Long /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 3622aedd662SScott Long /* highaddr */ BUS_SPACE_MAXADDR, 3632aedd662SScott Long /* filter */ NULL, 3642aedd662SScott Long /* filterarg */ NULL, 3652aedd662SScott Long /* maxsize */ IPS_MAX_IOBUF_SIZE, 3662aedd662SScott Long /* numsegs */ IPS_MAX_SG_ELEMENTS, 3672aedd662SScott Long /* maxsegsize*/ IPS_MAX_IOBUF_SIZE, 3682aedd662SScott Long /* flags */ 0, 369f6b1c44dSScott Long /* lockfunc */ busdma_lock_mutex, 37003a908f2SScott Long /* lockarg */ &sc->queue_mtx, 3712aedd662SScott Long &sc->sg_dmatag) != 0) { 3722aedd662SScott Long device_printf(sc->dev, "can't alloc SG dma tag\n"); 3732aedd662SScott Long goto error; 3742aedd662SScott Long } 3752aedd662SScott Long /* create one command buffer until we know how many commands this card 3762aedd662SScott Long can handle */ 3772aedd662SScott Long sc->max_cmds = 1; 3782aedd662SScott Long ips_cmdqueue_init(sc); 379dea4622dSScott Long callout_handle_init(&sc->timer); 3802aedd662SScott Long 3812aedd662SScott Long if(sc->ips_adapter_reinit(sc, 0)) 3822aedd662SScott Long goto error; 3832aedd662SScott Long 3847633e7f1SMartin Blapp /* initialize ffdc values */ 3857633e7f1SMartin Blapp microtime(&sc->ffdc_resettime); 3867633e7f1SMartin Blapp sc->ffdc_resetcount = 1; 3877633e7f1SMartin Blapp if ((i = ips_ffdc_reset(sc)) != 0) { 3887633e7f1SMartin Blapp device_printf(sc->dev, "failed to send ffdc reset to device (%d)\n", i); 3897633e7f1SMartin Blapp goto error; 3907633e7f1SMartin Blapp } 391dea4622dSScott Long if ((i = ips_get_adapter_info(sc)) != 0) { 392dea4622dSScott Long device_printf(sc->dev, "failed to get adapter configuration data from device (%d)\n", i); 393dea4622dSScott Long goto error; 394dea4622dSScott Long } 3957633e7f1SMartin Blapp ips_update_nvram(sc); /* no error check as failure doesn't matter */ 3967633e7f1SMartin Blapp if(sc->adapter_type > 0 && sc->adapter_type <= IPS_ADAPTER_MAX_T){ 3977633e7f1SMartin Blapp device_printf(sc->dev, "adapter type: %s\n", ips_adapter_name[sc->adapter_type]); 3987633e7f1SMartin Blapp } 399dea4622dSScott Long if ((i = ips_get_drive_info(sc)) != 0) { 400dea4622dSScott Long device_printf(sc->dev, "failed to get drive configuration data from device (%d)\n", i); 4012aedd662SScott Long goto error; 4022aedd662SScott Long } 4032aedd662SScott Long 4042aedd662SScott Long ips_cmdqueue_free(sc); 4052aedd662SScott Long if(sc->adapter_info.max_concurrent_cmds) 4062aedd662SScott Long sc->max_cmds = min(128, sc->adapter_info.max_concurrent_cmds); 4072aedd662SScott Long else 4082aedd662SScott Long sc->max_cmds = 32; 4092aedd662SScott Long if(ips_cmdqueue_init(sc)){ 4102aedd662SScott Long device_printf(sc->dev, "failed to initialize command buffers\n"); 4112aedd662SScott Long goto error; 4122aedd662SScott Long } 4132aedd662SScott Long sc->device_file = make_dev(&ips_cdevsw, device_get_unit(sc->dev), UID_ROOT, GID_OPERATOR, 4142aedd662SScott Long S_IRUSR | S_IWUSR, "ips%d", device_get_unit(sc->dev)); 4152aedd662SScott Long sc->device_file->si_drv1 = sc; 4162aedd662SScott Long ips_diskdev_init(sc); 4172aedd662SScott Long sc->timer = timeout(ips_timeout, sc, 10*hz); 4182aedd662SScott Long return 0; 4192aedd662SScott Long 4202aedd662SScott Long error: 4212aedd662SScott Long ips_adapter_free(sc); 4222aedd662SScott Long return ENXIO; 4232aedd662SScott Long } 4242aedd662SScott Long 4252aedd662SScott Long /* see if we should reinitialize the card and wait for it to timeout or complete initialization */ 4262aedd662SScott Long int ips_morpheus_reinit(ips_softc_t *sc, int force) 4272aedd662SScott Long { 4282aedd662SScott Long u_int32_t tmp; 4292aedd662SScott Long int i; 4302aedd662SScott Long 4312aedd662SScott Long tmp = ips_read_4(sc, MORPHEUS_REG_OISR); 4322aedd662SScott Long if(!force && (ips_read_4(sc, MORPHEUS_REG_OMR0) >= IPS_POST1_OK) && 4332aedd662SScott Long (ips_read_4(sc, MORPHEUS_REG_OMR1) != 0xdeadbeef) && !tmp){ 4342aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_OIMR, 0); 4352aedd662SScott Long return 0; 4362aedd662SScott Long } 4372aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_OIMR, 0xff); 4382aedd662SScott Long ips_read_4(sc, MORPHEUS_REG_OIMR); 4392aedd662SScott Long 4402aedd662SScott Long device_printf(sc->dev, "resetting adapter, this may take up to 5 minutes\n"); 4412aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_IDR, 0x80000000); 4422aedd662SScott Long DELAY(5000000); 4432aedd662SScott Long pci_read_config(sc->dev, 0, 4); 4442aedd662SScott Long 4452aedd662SScott Long tmp = ips_read_4(sc, MORPHEUS_REG_OISR); 4462aedd662SScott Long for(i = 0; i < 45 && !(tmp & MORPHEUS_BIT_POST1); i++){ 4472aedd662SScott Long DELAY(1000000); 4482aedd662SScott Long DEVICE_PRINTF(2, sc->dev, "post1: %d\n", i); 4492aedd662SScott Long tmp = ips_read_4(sc, MORPHEUS_REG_OISR); 4502aedd662SScott Long } 4512aedd662SScott Long if(tmp & MORPHEUS_BIT_POST1) 4522aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_OISR, MORPHEUS_BIT_POST1); 4532aedd662SScott Long 4542aedd662SScott Long if( i == 45 || ips_read_4(sc, MORPHEUS_REG_OMR0) < IPS_POST1_OK){ 4552aedd662SScott Long device_printf(sc->dev,"Adapter error during initialization.\n"); 4562aedd662SScott Long return 1; 4572aedd662SScott Long } 4582aedd662SScott Long for(i = 0; i < 240 && !(tmp & MORPHEUS_BIT_POST2); i++){ 4592aedd662SScott Long DELAY(1000000); 4602aedd662SScott Long DEVICE_PRINTF(2, sc->dev, "post2: %d\n", i); 4612aedd662SScott Long tmp = ips_read_4(sc, MORPHEUS_REG_OISR); 4622aedd662SScott Long } 4632aedd662SScott Long if(tmp & MORPHEUS_BIT_POST2) 4642aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_OISR, MORPHEUS_BIT_POST2); 4652aedd662SScott Long 4662aedd662SScott Long if(i == 240 || !ips_read_4(sc, MORPHEUS_REG_OMR1)){ 4672aedd662SScott Long device_printf(sc->dev, "adapter failed config check\n"); 4682aedd662SScott Long return 1; 4692aedd662SScott Long } 4702aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_OIMR, 0); 4712aedd662SScott Long if(force && ips_clear_adapter(sc)){ 4722aedd662SScott Long device_printf(sc->dev, "adapter clear failed\n"); 4732aedd662SScott Long return 1; 4742aedd662SScott Long } 4752aedd662SScott Long return 0; 4762aedd662SScott Long } 4772aedd662SScott Long 4782aedd662SScott Long /* clean up so we can unload the driver. */ 4792aedd662SScott Long int ips_adapter_free(ips_softc_t *sc) 4802aedd662SScott Long { 4812aedd662SScott Long int error = 0; 4822aedd662SScott Long if(sc->state & IPS_DEV_OPEN) 4832aedd662SScott Long return EBUSY; 4842aedd662SScott Long if((error = ips_diskdev_free(sc))) 4852aedd662SScott Long return error; 4862aedd662SScott Long if(ips_cmdqueue_free(sc)){ 4872aedd662SScott Long device_printf(sc->dev, 4882aedd662SScott Long "trying to exit when command queue is not empty!\n"); 4892aedd662SScott Long return EBUSY; 4902aedd662SScott Long } 4912aedd662SScott Long DEVICE_PRINTF(1, sc->dev, "free\n"); 4922aedd662SScott Long untimeout(ips_timeout, sc, sc->timer); 4932aedd662SScott Long 4942aedd662SScott Long if(sc->sg_dmatag) 4952aedd662SScott Long bus_dma_tag_destroy(sc->sg_dmatag); 4962aedd662SScott Long if(sc->command_dmatag) 4972aedd662SScott Long bus_dma_tag_destroy(sc->command_dmatag); 4982aedd662SScott Long if(sc->device_file) 4992aedd662SScott Long destroy_dev(sc->device_file); 5002aedd662SScott Long return 0; 5012aedd662SScott Long } 5022aedd662SScott Long 5037765040eSScott Long static __inline int ips_morpheus_check_intr(ips_softc_t *sc) 5042aedd662SScott Long { 5052aedd662SScott Long int cmdnumber; 5062aedd662SScott Long ips_cmd_status_t status; 5077765040eSScott Long ips_command_t *command; 5087765040eSScott Long int found = 0; 5097765040eSScott Long u_int32_t oisr; 5102aedd662SScott Long 5112aedd662SScott Long oisr = ips_read_4(sc, MORPHEUS_REG_OISR); 5127765040eSScott Long PRINTF(9, "interrupt registers out:%x\n", oisr); 5132aedd662SScott Long if(!(oisr & MORPHEUS_BIT_CMD_IRQ)){ 5142aedd662SScott Long DEVICE_PRINTF(2,sc->dev, "got a non-command irq\n"); 51503a908f2SScott Long mtx_unlock(&sc->queue_mtx); 5167765040eSScott Long return (0); 5172aedd662SScott Long } 5182aedd662SScott Long while((status.value = ips_read_4(sc, MORPHEUS_REG_OQPR)) != 0xffffffff){ 5192aedd662SScott Long cmdnumber = status.fields.command_id; 5207765040eSScott Long command = &sc->commandarray[cmdnumber]; 5217765040eSScott Long command->status.value = status.value; 5227765040eSScott Long command->timeout = 0; 5237765040eSScott Long command->callback(command); 5242aedd662SScott Long 5257765040eSScott Long found = 1; 5262aedd662SScott Long } 5277765040eSScott Long return (found); 5287765040eSScott Long } 5297765040eSScott Long 5307765040eSScott Long void ips_morpheus_intr(void *void_sc) 5317765040eSScott Long { 5327765040eSScott Long ips_softc_t *sc = void_sc; 5337765040eSScott Long 5347765040eSScott Long mtx_lock(&sc->queue_mtx); 5357765040eSScott Long ips_morpheus_check_intr(sc); 53603a908f2SScott Long mtx_unlock(&sc->queue_mtx); 5377765040eSScott Long } 5387765040eSScott Long 5397765040eSScott Long void ips_morpheus_poll(ips_command_t *command) 5407765040eSScott Long { 5417765040eSScott Long uint32_t ts; 5427765040eSScott Long 5437765040eSScott Long ts = time_second + command->timeout; 5447765040eSScott Long while ((command->timeout != 0) 5457765040eSScott Long && (ips_morpheus_check_intr(command->sc) == 0) 5467765040eSScott Long && (ts > time_second)) 5477765040eSScott Long DELAY(1000); 5482aedd662SScott Long } 5492aedd662SScott Long 5502aedd662SScott Long void ips_issue_morpheus_cmd(ips_command_t *command) 5512aedd662SScott Long { 5522aedd662SScott Long /* hmmm, is there a cleaner way to do this? */ 5532aedd662SScott Long if(command->sc->state & IPS_OFFLINE){ 5542aedd662SScott Long command->status.value = IPS_ERROR_STATUS; 5552aedd662SScott Long command->callback(command); 5562aedd662SScott Long return; 5572aedd662SScott Long } 5582aedd662SScott Long command->timeout = 10; 5592aedd662SScott Long ips_write_4(command->sc, MORPHEUS_REG_IQPR, command->command_phys_addr); 5602aedd662SScott Long } 5612aedd662SScott Long 5622aedd662SScott Long static void ips_copperhead_queue_callback(void *queueptr, bus_dma_segment_t *segments,int segnum, int error) 5632aedd662SScott Long { 5642aedd662SScott Long ips_copper_queue_t *queue = queueptr; 5652aedd662SScott Long if(error){ 5662aedd662SScott Long return; 5672aedd662SScott Long } 5682aedd662SScott Long queue->base_phys_addr = segments[0].ds_addr; 5692aedd662SScott Long } 5702aedd662SScott Long 5712aedd662SScott Long static int ips_copperhead_queue_init(ips_softc_t *sc) 5722aedd662SScott Long { 5732aedd662SScott Long int error; 5742aedd662SScott Long bus_dma_tag_t dmatag; 5752aedd662SScott Long bus_dmamap_t dmamap; 5762aedd662SScott Long if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 5772aedd662SScott Long /* alignemnt */ 1, 5782aedd662SScott Long /* boundary */ 0, 5792aedd662SScott Long /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 5802aedd662SScott Long /* highaddr */ BUS_SPACE_MAXADDR, 5812aedd662SScott Long /* filter */ NULL, 5822aedd662SScott Long /* filterarg */ NULL, 5832aedd662SScott Long /* maxsize */ sizeof(ips_copper_queue_t), 5842aedd662SScott Long /* numsegs */ 1, 5852aedd662SScott Long /* maxsegsize*/ sizeof(ips_copper_queue_t), 5862aedd662SScott Long /* flags */ 0, 58703a908f2SScott Long /* lockfunc */ NULL, 58803a908f2SScott Long /* lockarg */ NULL, 5892aedd662SScott Long &dmatag) != 0) { 5902aedd662SScott Long device_printf(sc->dev, "can't alloc dma tag for statue queue\n"); 5912aedd662SScott Long error = ENOMEM; 5922aedd662SScott Long goto exit; 5932aedd662SScott Long } 5942aedd662SScott Long if(bus_dmamem_alloc(dmatag, (void *)&(sc->copper_queue), 5952aedd662SScott Long BUS_DMA_NOWAIT, &dmamap)){ 5962aedd662SScott Long error = ENOMEM; 5972aedd662SScott Long goto exit; 5982aedd662SScott Long } 5992aedd662SScott Long bzero(sc->copper_queue, sizeof(ips_copper_queue_t)); 6002aedd662SScott Long sc->copper_queue->dmatag = dmatag; 6012aedd662SScott Long sc->copper_queue->dmamap = dmamap; 6022aedd662SScott Long sc->copper_queue->nextstatus = 1; 6032aedd662SScott Long bus_dmamap_load(dmatag, dmamap, 6042aedd662SScott Long &(sc->copper_queue->status[0]), IPS_MAX_CMD_NUM * 4, 6052aedd662SScott Long ips_copperhead_queue_callback, sc->copper_queue, 6062aedd662SScott Long BUS_DMA_NOWAIT); 6072aedd662SScott Long if(sc->copper_queue->base_phys_addr == 0){ 6082aedd662SScott Long error = ENOMEM; 6092aedd662SScott Long goto exit; 6102aedd662SScott Long } 6112aedd662SScott Long ips_write_4(sc, COPPER_REG_SQSR, sc->copper_queue->base_phys_addr); 6122aedd662SScott Long ips_write_4(sc, COPPER_REG_SQER, sc->copper_queue->base_phys_addr + 6132aedd662SScott Long IPS_MAX_CMD_NUM * 4); 6142aedd662SScott Long ips_write_4(sc, COPPER_REG_SQHR, sc->copper_queue->base_phys_addr + 4); 6152aedd662SScott Long ips_write_4(sc, COPPER_REG_SQTR, sc->copper_queue->base_phys_addr); 6162aedd662SScott Long 6172aedd662SScott Long 6182aedd662SScott Long return 0; 6192aedd662SScott Long exit: 6202aedd662SScott Long bus_dmamem_free(dmatag, sc->copper_queue, dmamap); 6212aedd662SScott Long bus_dma_tag_destroy(dmatag); 6222aedd662SScott Long return error; 6232aedd662SScott Long } 6242aedd662SScott Long 6252aedd662SScott Long /* see if we should reinitialize the card and wait for it to timeout or complete initialization FIXME */ 6262aedd662SScott Long int ips_copperhead_reinit(ips_softc_t *sc, int force) 6272aedd662SScott Long { 6282aedd662SScott Long int i, j; 6292aedd662SScott Long u_int32_t postcode = 0, configstatus = 0; 6302aedd662SScott Long ips_write_1(sc, COPPER_REG_SCPR, 0x80); 6312aedd662SScott Long ips_write_1(sc, COPPER_REG_SCPR, 0); 6322aedd662SScott Long device_printf(sc->dev, "reinitializing adapter, this could take several minutes.\n"); 6332aedd662SScott Long for(j = 0; j < 2; j++){ 6342aedd662SScott Long postcode <<= 8; 6352aedd662SScott Long for(i = 0; i < 45; i++){ 6362aedd662SScott Long if(ips_read_1(sc, COPPER_REG_HISR) & COPPER_GHI_BIT){ 6372aedd662SScott Long postcode |= ips_read_1(sc, COPPER_REG_ISPR); 6382aedd662SScott Long ips_write_1(sc, COPPER_REG_HISR, 6392aedd662SScott Long COPPER_GHI_BIT); 6402aedd662SScott Long break; 6412aedd662SScott Long } else 6422aedd662SScott Long DELAY(1000000); 6432aedd662SScott Long } 6442aedd662SScott Long if(i == 45) 6452aedd662SScott Long return 1; 6462aedd662SScott Long } 6472aedd662SScott Long for(j = 0; j < 2; j++){ 6482aedd662SScott Long configstatus <<= 8; 6492aedd662SScott Long for(i = 0; i < 240; i++){ 6502aedd662SScott Long if(ips_read_1(sc, COPPER_REG_HISR) & COPPER_GHI_BIT){ 6512aedd662SScott Long configstatus |= ips_read_1(sc, COPPER_REG_ISPR); 6522aedd662SScott Long ips_write_1(sc, COPPER_REG_HISR, 6532aedd662SScott Long COPPER_GHI_BIT); 6542aedd662SScott Long break; 6552aedd662SScott Long } else 6562aedd662SScott Long DELAY(1000000); 6572aedd662SScott Long } 6582aedd662SScott Long if(i == 240) 6592aedd662SScott Long return 1; 6602aedd662SScott Long } 6612aedd662SScott Long for(i = 0; i < 240; i++){ 6622aedd662SScott Long if(!(ips_read_1(sc, COPPER_REG_CBSP) & COPPER_OP_BIT)){ 6632aedd662SScott Long break; 6642aedd662SScott Long } else 6652aedd662SScott Long DELAY(1000000); 6662aedd662SScott Long } 6672aedd662SScott Long if(i == 240) 6682aedd662SScott Long return 1; 6692aedd662SScott Long ips_write_2(sc, COPPER_REG_CCCR, 0x1000 | COPPER_ILE_BIT); 6702aedd662SScott Long ips_write_1(sc, COPPER_REG_SCPR, COPPER_EBM_BIT); 6712aedd662SScott Long ips_copperhead_queue_init(sc); 6722aedd662SScott Long ips_write_1(sc, COPPER_REG_HISR, COPPER_GHI_BIT); 6732aedd662SScott Long i = ips_read_1(sc, COPPER_REG_SCPR); 6742aedd662SScott Long ips_write_1(sc, COPPER_REG_HISR, COPPER_EI_BIT); 6752aedd662SScott Long if(!configstatus){ 6762aedd662SScott Long device_printf(sc->dev, "adapter initialization failed\n"); 6772aedd662SScott Long return 1; 6782aedd662SScott Long } 6792aedd662SScott Long if(force && ips_clear_adapter(sc)){ 6802aedd662SScott Long device_printf(sc->dev, "adapter clear failed\n"); 6812aedd662SScott Long return 1; 6822aedd662SScott Long } 6832aedd662SScott Long return 0; 6842aedd662SScott Long } 6852aedd662SScott Long static u_int32_t ips_copperhead_cmd_status(ips_softc_t *sc) 6862aedd662SScott Long { 6872aedd662SScott Long u_int32_t value; 6882aedd662SScott Long int statnum = sc->copper_queue->nextstatus++; 6892aedd662SScott Long if(sc->copper_queue->nextstatus == IPS_MAX_CMD_NUM) 6902aedd662SScott Long sc->copper_queue->nextstatus = 0; 6912aedd662SScott Long value = sc->copper_queue->status[statnum]; 6922aedd662SScott Long ips_write_4(sc, COPPER_REG_SQTR, sc->copper_queue->base_phys_addr + 6932aedd662SScott Long 4 * statnum); 6942aedd662SScott Long return value; 6952aedd662SScott Long } 6962aedd662SScott Long 6972aedd662SScott Long 6982aedd662SScott Long void ips_copperhead_intr(void *void_sc) 6992aedd662SScott Long { 7002aedd662SScott Long ips_softc_t *sc = (ips_softc_t *)void_sc; 7012aedd662SScott Long int cmdnumber; 7022aedd662SScott Long ips_cmd_status_t status; 7032aedd662SScott Long 70403a908f2SScott Long mtx_lock(&sc->queue_mtx); 7052aedd662SScott Long while(ips_read_1(sc, COPPER_REG_HISR) & COPPER_SCE_BIT){ 7062aedd662SScott Long status.value = ips_copperhead_cmd_status(sc); 7072aedd662SScott Long cmdnumber = status.fields.command_id; 7082aedd662SScott Long sc->commandarray[cmdnumber].status.value = status.value; 7092aedd662SScott Long sc->commandarray[cmdnumber].timeout = 0; 7102aedd662SScott Long sc->commandarray[cmdnumber].callback(&(sc->commandarray[cmdnumber])); 7112aedd662SScott Long PRINTF(9, "ips: got command %d\n", cmdnumber); 7122aedd662SScott Long } 71303a908f2SScott Long mtx_unlock(&sc->queue_mtx); 7142aedd662SScott Long return; 7152aedd662SScott Long } 7162aedd662SScott Long 7172aedd662SScott Long void ips_issue_copperhead_cmd(ips_command_t *command) 7182aedd662SScott Long { 7192aedd662SScott Long int i; 7202aedd662SScott Long /* hmmm, is there a cleaner way to do this? */ 7212aedd662SScott Long if(command->sc->state & IPS_OFFLINE){ 7222aedd662SScott Long command->status.value = IPS_ERROR_STATUS; 7232aedd662SScott Long command->callback(command); 7242aedd662SScott Long return; 7252aedd662SScott Long } 7262aedd662SScott Long command->timeout = 10; 7272aedd662SScott Long for(i = 0; ips_read_4(command->sc, COPPER_REG_CCCR) & COPPER_SEM_BIT; 7282aedd662SScott Long i++ ){ 7292aedd662SScott Long if( i == 20){ 7302aedd662SScott Long printf("sem bit still set, can't send a command\n"); 7312aedd662SScott Long return; 7322aedd662SScott Long } 7332aedd662SScott Long DELAY(500);/* need to do a delay here */ 7342aedd662SScott Long } 7352aedd662SScott Long ips_write_4(command->sc, COPPER_REG_CCSAR, command->command_phys_addr); 7362aedd662SScott Long ips_write_2(command->sc, COPPER_REG_CCCR, COPPER_CMD_START); 7372aedd662SScott Long } 7382aedd662SScott Long 7397765040eSScott Long void ips_copperhead_poll(ips_command_t *command) 7407765040eSScott Long { 7417765040eSScott Long 7427765040eSScott Long printf("ips: cmd polling not implemented for copperhead devices\n"); 7437765040eSScott Long } 744