12aedd662SScott Long /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3718cf2ccSPedro F. Giffuni * 4aad970f1SDavid E. O'Brien * Written by: David Jeffery 52aedd662SScott Long * Copyright (c) 2002 Adaptec Inc. 62aedd662SScott Long * All rights reserved. 72aedd662SScott Long * 82aedd662SScott Long * Redistribution and use in source and binary forms, with or without 92aedd662SScott Long * modification, are permitted provided that the following conditions 102aedd662SScott Long * are met: 112aedd662SScott Long * 1. Redistributions of source code must retain the above copyright 122aedd662SScott Long * notice, this list of conditions and the following disclaimer. 132aedd662SScott Long * 2. Redistributions in binary form must reproduce the above copyright 142aedd662SScott Long * notice, this list of conditions and the following disclaimer in the 152aedd662SScott Long * documentation and/or other materials provided with the distribution. 162aedd662SScott Long * 172aedd662SScott Long * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 182aedd662SScott Long * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 192aedd662SScott Long * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 202aedd662SScott Long * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 212aedd662SScott Long * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 222aedd662SScott Long * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 232aedd662SScott Long * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 242aedd662SScott Long * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 252aedd662SScott Long * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 262aedd662SScott Long * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 272aedd662SScott Long * SUCH DAMAGE. 282aedd662SScott Long */ 292aedd662SScott Long 30aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 31aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 322aedd662SScott Long 33*e2e050c8SConrad Meyer #include <sys/types.h> 34*e2e050c8SConrad Meyer #include <sys/lock.h> 35*e2e050c8SConrad Meyer #include <sys/mutex.h> 362aedd662SScott Long #include <sys/stat.h> 372aedd662SScott Long #include <sys/time.h> 382aedd662SScott Long 39*e2e050c8SConrad Meyer #include <dev/ips/ipsreg.h> 40*e2e050c8SConrad Meyer #include <dev/ips/ips.h> 41*e2e050c8SConrad Meyer 422aedd662SScott Long static d_open_t ips_open; 432aedd662SScott Long static d_close_t ips_close; 442aedd662SScott Long static d_ioctl_t ips_ioctl; 452aedd662SScott Long 46dd83a01eSScott Long MALLOC_DEFINE(M_IPSBUF, "ipsbuf","IPS driver buffer"); 47dd83a01eSScott Long 482aedd662SScott Long static struct cdevsw ips_cdevsw = { 49dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 502aedd662SScott Long .d_open = ips_open, 512aedd662SScott Long .d_close = ips_close, 522aedd662SScott Long .d_ioctl = ips_ioctl, 532aedd662SScott Long .d_name = "ips", 542aedd662SScott Long }; 552aedd662SScott Long 567633e7f1SMartin Blapp static const char* ips_adapter_name[] = { 577633e7f1SMartin Blapp "N/A", 587633e7f1SMartin Blapp "ServeRAID (copperhead)", 597633e7f1SMartin Blapp "ServeRAID II (copperhead refresh)", 607633e7f1SMartin Blapp "ServeRAID onboard (copperhead)", 617633e7f1SMartin Blapp "ServeRAID onboard (copperhead)", 627633e7f1SMartin Blapp "ServeRAID 3H (clarinet)", 637633e7f1SMartin Blapp "ServeRAID 3L (clarinet lite)", 647633e7f1SMartin Blapp "ServeRAID 4H (trombone)", 657633e7f1SMartin Blapp "ServeRAID 4M (morpheus)", 667633e7f1SMartin Blapp "ServeRAID 4L (morpheus lite)", 677633e7f1SMartin Blapp "ServeRAID 4Mx (neo)", 687633e7f1SMartin Blapp "ServeRAID 4Lx (neo lite)", 697633e7f1SMartin Blapp "ServeRAID 5i II (sarasota)", 707633e7f1SMartin Blapp "ServeRAID 5i (sarasota)", 717633e7f1SMartin Blapp "ServeRAID 6M (marco)", 72bd4fb874SMaxim Konovalov "ServeRAID 6i (sebring)", 73bd4fb874SMaxim Konovalov "ServeRAID 7t", 74bd4fb874SMaxim Konovalov "ServeRAID 7k", 75bd4fb874SMaxim Konovalov "ServeRAID 7M" 767633e7f1SMartin Blapp }; 777633e7f1SMartin Blapp 782aedd662SScott Long 7989c9c53dSPoul-Henning Kamp static int ips_open(struct cdev *dev, int flags, int fmt, struct thread *td) 802aedd662SScott Long { 812aedd662SScott Long ips_softc_t *sc = dev->si_drv1; 82352176c8SJohn Baldwin mtx_lock(&sc->queue_mtx); 832aedd662SScott Long sc->state |= IPS_DEV_OPEN; 84352176c8SJohn Baldwin mtx_unlock(&sc->queue_mtx); 852aedd662SScott Long return 0; 862aedd662SScott Long } 872aedd662SScott Long 8889c9c53dSPoul-Henning Kamp static int ips_close(struct cdev *dev, int flags, int fmt, struct thread *td) 892aedd662SScott Long { 902aedd662SScott Long ips_softc_t *sc = dev->si_drv1; 91352176c8SJohn Baldwin 92352176c8SJohn Baldwin mtx_lock(&sc->queue_mtx); 932aedd662SScott Long sc->state &= ~IPS_DEV_OPEN; 94352176c8SJohn Baldwin mtx_unlock(&sc->queue_mtx); 952aedd662SScott Long 962aedd662SScott Long return 0; 972aedd662SScott Long } 982aedd662SScott Long 9989c9c53dSPoul-Henning Kamp static int ips_ioctl(struct cdev *dev, u_long command, caddr_t addr, int32_t flags, struct thread *td) 1002aedd662SScott Long { 1012aedd662SScott Long ips_softc_t *sc; 1022aedd662SScott Long 1032aedd662SScott Long sc = dev->si_drv1; 1042aedd662SScott Long return ips_ioctl_request(sc, command, addr, flags); 1052aedd662SScott Long } 1062aedd662SScott Long 1072aedd662SScott Long static void ips_cmd_dmaload(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error) 1082aedd662SScott Long { 1092aedd662SScott Long ips_command_t *command = cmdptr; 1102aedd662SScott Long PRINTF(10, "ips: in ips_cmd_dmaload\n"); 1112aedd662SScott Long if(!error) 1122aedd662SScott Long command->command_phys_addr = segments[0].ds_addr; 1132aedd662SScott Long 1142aedd662SScott Long } 1152aedd662SScott Long 116453130d9SPedro F. Giffuni /* is locking needed? what locking guarantees are there on removal? */ 11703a908f2SScott Long static int ips_cmdqueue_free(ips_softc_t *sc) 1182aedd662SScott Long { 1192aedd662SScott Long int i, error = -1; 120b234a120SScott Long ips_command_t *command; 121b234a120SScott Long 1222aedd662SScott Long if(!sc->used_commands){ 1232aedd662SScott Long for(i = 0; i < sc->max_cmds; i++){ 124b234a120SScott Long 125b234a120SScott Long command = &sc->commandarray[i]; 126b234a120SScott Long 127b234a120SScott Long if(command->command_phys_addr == 0) 1282aedd662SScott Long continue; 1292aedd662SScott Long bus_dmamap_unload(sc->command_dmatag, 130b234a120SScott Long command->command_dmamap); 1312aedd662SScott Long bus_dmamem_free(sc->command_dmatag, 132b234a120SScott Long command->command_buffer, 133b234a120SScott Long command->command_dmamap); 13403a908f2SScott Long if (command->data_dmamap != NULL) 13503a908f2SScott Long bus_dmamap_destroy(command->data_dmatag, 13603a908f2SScott Long command->data_dmamap); 1372aedd662SScott Long } 1382aedd662SScott Long error = 0; 1392aedd662SScott Long sc->state |= IPS_OFFLINE; 1402aedd662SScott Long } 14103a908f2SScott Long sc->staticcmd = NULL; 14203a908f2SScott Long free(sc->commandarray, M_DEVBUF); 1432aedd662SScott Long return error; 1442aedd662SScott Long } 1452aedd662SScott Long 1462aedd662SScott Long /* places all ips command structs on the free command queue. No locking as if someone else tries 1472aedd662SScott Long * to access this during init, we have bigger problems */ 14803a908f2SScott Long static int ips_cmdqueue_init(ips_softc_t *sc) 1492aedd662SScott Long { 1502aedd662SScott Long int i; 1512aedd662SScott Long ips_command_t *command; 15203a908f2SScott Long 15303a908f2SScott Long sc->commandarray = (ips_command_t *)malloc(sizeof(ips_command_t) * 15403a908f2SScott Long sc->max_cmds, M_DEVBUF, M_NOWAIT|M_ZERO); 15503a908f2SScott Long if (sc->commandarray == NULL) 15603a908f2SScott Long return (ENOMEM); 15703a908f2SScott Long 1582aedd662SScott Long SLIST_INIT(&sc->free_cmd_list); 1592aedd662SScott Long for(i = 0; i < sc->max_cmds; i++){ 1602aedd662SScott Long command = &sc->commandarray[i]; 161b234a120SScott Long command->id = i; 162b234a120SScott Long command->sc = sc; 163b234a120SScott Long 1642aedd662SScott Long if(bus_dmamem_alloc(sc->command_dmatag,&command->command_buffer, 1652aedd662SScott Long BUS_DMA_NOWAIT, &command->command_dmamap)) 1662aedd662SScott Long goto error; 1672aedd662SScott Long bus_dmamap_load(sc->command_dmatag, command->command_dmamap, 1682aedd662SScott Long command->command_buffer,IPS_COMMAND_LEN, 1692aedd662SScott Long ips_cmd_dmaload, command, BUS_DMA_NOWAIT); 1702aedd662SScott Long if(!command->command_phys_addr){ 1712aedd662SScott Long bus_dmamem_free(sc->command_dmatag, 1722aedd662SScott Long command->command_buffer, command->command_dmamap); 1732aedd662SScott Long goto error; 1742aedd662SScott Long } 175b234a120SScott Long 17603a908f2SScott Long if (i != 0) { 17703a908f2SScott Long command->data_dmatag = sc->sg_dmatag; 17803a908f2SScott Long if (bus_dmamap_create(command->data_dmatag, 0, 17903a908f2SScott Long &command->data_dmamap)) 18003a908f2SScott Long goto error; 181b234a120SScott Long SLIST_INSERT_HEAD(&sc->free_cmd_list, command, next); 18203a908f2SScott Long } else 18303a908f2SScott Long sc->staticcmd = command; 1842aedd662SScott Long } 1852aedd662SScott Long sc->state &= ~IPS_OFFLINE; 1862aedd662SScott Long return 0; 1872aedd662SScott Long error: 1882aedd662SScott Long ips_cmdqueue_free(sc); 1892aedd662SScott Long return ENOMEM; 1902aedd662SScott Long } 1912aedd662SScott Long 1922aedd662SScott Long /* returns a free command struct if one is available. 1932aedd662SScott Long * It also blanks out anything that may be a wild pointer/value. 1942aedd662SScott Long * Also, command buffers are not freed. They are 1952aedd662SScott Long * small so they are saved and kept dmamapped and loaded. 1962aedd662SScott Long */ 19703a908f2SScott Long int ips_get_free_cmd(ips_softc_t *sc, ips_command_t **cmd, unsigned long flags) 1982aedd662SScott Long { 1992aedd662SScott Long ips_command_t *command; 2002aedd662SScott Long 2012aedd662SScott Long if(sc->state & IPS_OFFLINE){ 2022aedd662SScott Long return EIO; 2032aedd662SScott Long } 20403a908f2SScott Long if ((flags & IPS_STATIC_FLAG) == 0) { 2052aedd662SScott Long command = SLIST_FIRST(&sc->free_cmd_list); 2062aedd662SScott Long if(!command || (sc->state & IPS_TIMEOUT)){ 20703a908f2SScott Long return EBUSY; 2082aedd662SScott Long } 2092aedd662SScott Long SLIST_REMOVE_HEAD(&sc->free_cmd_list, next); 2102aedd662SScott Long (sc->used_commands)++; 21103a908f2SScott Long } else { 21203a908f2SScott Long if (sc->state & IPS_STATIC_BUSY) 21303a908f2SScott Long return EAGAIN; 21403a908f2SScott Long command = sc->staticcmd; 21503a908f2SScott Long sc->state |= IPS_STATIC_BUSY; 21603a908f2SScott Long } 2172aedd662SScott Long clear_ips_command(command); 2182aedd662SScott Long bzero(command->command_buffer, IPS_COMMAND_LEN); 21903a908f2SScott Long *cmd = command; 22003a908f2SScott Long return 0; 2212aedd662SScott Long } 2222aedd662SScott Long 2232aedd662SScott Long /* adds a command back to the free command queue */ 2242aedd662SScott Long void ips_insert_free_cmd(ips_softc_t *sc, ips_command_t *command) 2252aedd662SScott Long { 226b234a120SScott Long 22703a908f2SScott Long if (sema_value(&sc->cmd_sema) != 0) 228b234a120SScott Long panic("ips: command returned non-zero semaphore"); 229b234a120SScott Long 23003a908f2SScott Long if (command != sc->staticcmd) { 2312aedd662SScott Long SLIST_INSERT_HEAD(&sc->free_cmd_list, command, next); 2322aedd662SScott Long (sc->used_commands)--; 23303a908f2SScott Long } else { 23403a908f2SScott Long sc->state &= ~IPS_STATIC_BUSY; 23503a908f2SScott Long } 2362aedd662SScott Long } 2377633e7f1SMartin Blapp static const char* ips_diskdev_statename(u_int8_t state) 2387633e7f1SMartin Blapp { 2397633e7f1SMartin Blapp static char statebuf[20]; 2407633e7f1SMartin Blapp switch(state){ 2417633e7f1SMartin Blapp case IPS_LD_OFFLINE: 2427633e7f1SMartin Blapp return("OFFLINE"); 2437633e7f1SMartin Blapp break; 2447633e7f1SMartin Blapp case IPS_LD_OKAY: 2457633e7f1SMartin Blapp return("OK"); 2467633e7f1SMartin Blapp break; 2477633e7f1SMartin Blapp case IPS_LD_DEGRADED: 2487633e7f1SMartin Blapp return("DEGRADED"); 2497633e7f1SMartin Blapp break; 2507633e7f1SMartin Blapp case IPS_LD_FREE: 2517633e7f1SMartin Blapp return("FREE"); 2527633e7f1SMartin Blapp break; 2537633e7f1SMartin Blapp case IPS_LD_SYS: 2547633e7f1SMartin Blapp return("SYS"); 2557633e7f1SMartin Blapp break; 2567633e7f1SMartin Blapp case IPS_LD_CRS: 2577633e7f1SMartin Blapp return("CRS"); 2587633e7f1SMartin Blapp break; 2597633e7f1SMartin Blapp } 2607633e7f1SMartin Blapp sprintf(statebuf,"UNKNOWN(0x%02x)", state); 2617633e7f1SMartin Blapp return(statebuf); 2627633e7f1SMartin Blapp } 2632aedd662SScott Long 2642aedd662SScott Long static int ips_diskdev_init(ips_softc_t *sc) 2652aedd662SScott Long { 2662aedd662SScott Long int i; 2672aedd662SScott Long for(i=0; i < IPS_MAX_NUM_DRIVES; i++){ 2687633e7f1SMartin Blapp if(sc->drives[i].state == IPS_LD_FREE) continue; 2697633e7f1SMartin Blapp device_printf(sc->dev, "Logical Drive %d: RAID%d sectors: %u, state %s\n", 2707633e7f1SMartin Blapp i, sc->drives[i].raid_lvl, 2717633e7f1SMartin Blapp sc->drives[i].sector_count, 2727633e7f1SMartin Blapp ips_diskdev_statename(sc->drives[i].state)); 2737633e7f1SMartin Blapp if(sc->drives[i].state == IPS_LD_OKAY || 2747633e7f1SMartin Blapp sc->drives[i].state == IPS_LD_DEGRADED){ 2752aedd662SScott Long sc->diskdev[i] = device_add_child(sc->dev, NULL, -1); 276f472527cSPeter Wemm device_set_ivars(sc->diskdev[i],(void *)(uintptr_t) i); 2772aedd662SScott Long } 2782aedd662SScott Long } 2792aedd662SScott Long if(bus_generic_attach(sc->dev)){ 2802aedd662SScott Long device_printf(sc->dev, "Attaching bus failed\n"); 2812aedd662SScott Long } 2822aedd662SScott Long return 0; 2832aedd662SScott Long } 2842aedd662SScott Long 2852aedd662SScott Long static int ips_diskdev_free(ips_softc_t *sc) 2862aedd662SScott Long { 2872aedd662SScott Long int i; 2882aedd662SScott Long int error = 0; 2892aedd662SScott Long for(i = 0; i < IPS_MAX_NUM_DRIVES; i++){ 2902aedd662SScott Long if(sc->diskdev[i]) 2912aedd662SScott Long error = device_delete_child(sc->dev, sc->diskdev[i]); 2922aedd662SScott Long if(error) 2932aedd662SScott Long return error; 2942aedd662SScott Long } 2952aedd662SScott Long bus_generic_detach(sc->dev); 2962aedd662SScott Long return 0; 2972aedd662SScott Long } 2982aedd662SScott Long 2992aedd662SScott Long /* ips_timeout is periodically called to make sure no commands sent 3002aedd662SScott Long * to the card have become stuck. If it finds a stuck command, it 3012aedd662SScott Long * sets a flag so the driver won't start any more commands and then 3022aedd662SScott Long * is periodically called to see if all outstanding commands have 3032aedd662SScott Long * either finished or timed out. Once timed out, an attempt to 3042aedd662SScott Long * reinitialize the card is made. If that fails, the driver gives 3052aedd662SScott Long * up and declares the card dead. */ 3062aedd662SScott Long static void ips_timeout(void *arg) 3072aedd662SScott Long { 3082aedd662SScott Long ips_softc_t *sc = arg; 3092aedd662SScott Long int i, state = 0; 3102aedd662SScott Long ips_command_t *command; 31103a908f2SScott Long 312352176c8SJohn Baldwin mtx_assert(&sc->queue_mtx, MA_OWNED); 3132aedd662SScott Long command = &sc->commandarray[0]; 3142aedd662SScott Long for(i = 0; i < sc->max_cmds; i++){ 3152aedd662SScott Long if(!command[i].timeout){ 3162aedd662SScott Long continue; 3172aedd662SScott Long } 3182aedd662SScott Long command[i].timeout--; 3192aedd662SScott Long if(!command[i].timeout){ 3202aedd662SScott Long if(!(sc->state & IPS_TIMEOUT)){ 3212aedd662SScott Long sc->state |= IPS_TIMEOUT; 3222aedd662SScott Long device_printf(sc->dev, "WARNING: command timeout. Adapter is in toaster mode, resetting to known state\n"); 3232aedd662SScott Long } 3242eea7051SScott Long ips_set_error(&command[i], ETIMEDOUT); 3252aedd662SScott Long command[i].callback(&command[i]); 3262aedd662SScott Long /* hmm, this should be enough cleanup */ 3272aedd662SScott Long } else 3282aedd662SScott Long state = 1; 3292aedd662SScott Long } 3302aedd662SScott Long if(!state && (sc->state & IPS_TIMEOUT)){ 3312aedd662SScott Long if(sc->ips_adapter_reinit(sc, 1)){ 3322aedd662SScott Long device_printf(sc->dev, "AIEE! adapter reset failed, giving up and going home! Have a nice day.\n"); 3332aedd662SScott Long sc->state |= IPS_OFFLINE; 3342aedd662SScott Long sc->state &= ~IPS_TIMEOUT; 3352aedd662SScott Long /* Grr, I hate this solution. I run waiting commands 3362aedd662SScott Long one at a time and error them out just before they 3372aedd662SScott Long would go to the card. This sucks. */ 3382aedd662SScott Long } else 3392aedd662SScott Long sc->state &= ~IPS_TIMEOUT; 3402aedd662SScott Long } 3412aedd662SScott Long if (sc->state != IPS_OFFLINE) 342352176c8SJohn Baldwin callout_reset(&sc->timer, 10 * hz, ips_timeout, sc); 3432aedd662SScott Long } 3442aedd662SScott Long 3452aedd662SScott Long /* check card and initialize it */ 3462aedd662SScott Long int ips_adapter_init(ips_softc_t *sc) 3472aedd662SScott Long { 348dea4622dSScott Long int i; 3492aedd662SScott Long DEVICE_PRINTF(1,sc->dev, "initializing\n"); 350b234a120SScott Long 3512aedd662SScott Long if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 3522aedd662SScott Long /* alignemnt */ 1, 3532aedd662SScott Long /* boundary */ 0, 3542aedd662SScott Long /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 3552aedd662SScott Long /* highaddr */ BUS_SPACE_MAXADDR, 3562aedd662SScott Long /* filter */ NULL, 3572aedd662SScott Long /* filterarg */ NULL, 3582aedd662SScott Long /* maxsize */ IPS_COMMAND_LEN + 3592aedd662SScott Long IPS_MAX_SG_LEN, 3602aedd662SScott Long /* numsegs */ 1, 3612aedd662SScott Long /* maxsegsize*/ IPS_COMMAND_LEN + 3622aedd662SScott Long IPS_MAX_SG_LEN, 3632aedd662SScott Long /* flags */ 0, 36403a908f2SScott Long /* lockfunc */ NULL, 36503a908f2SScott Long /* lockarg */ NULL, 3662aedd662SScott Long &sc->command_dmatag) != 0) { 3672aedd662SScott Long device_printf(sc->dev, "can't alloc command dma tag\n"); 3682aedd662SScott Long goto error; 3692aedd662SScott Long } 3702aedd662SScott Long if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 3712aedd662SScott Long /* alignemnt */ 1, 3722aedd662SScott Long /* boundary */ 0, 3732aedd662SScott Long /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 3742aedd662SScott Long /* highaddr */ BUS_SPACE_MAXADDR, 3752aedd662SScott Long /* filter */ NULL, 3762aedd662SScott Long /* filterarg */ NULL, 3772aedd662SScott Long /* maxsize */ IPS_MAX_IOBUF_SIZE, 3782aedd662SScott Long /* numsegs */ IPS_MAX_SG_ELEMENTS, 3792aedd662SScott Long /* maxsegsize*/ IPS_MAX_IOBUF_SIZE, 3802aedd662SScott Long /* flags */ 0, 381f6b1c44dSScott Long /* lockfunc */ busdma_lock_mutex, 38203a908f2SScott Long /* lockarg */ &sc->queue_mtx, 3832aedd662SScott Long &sc->sg_dmatag) != 0) { 3842aedd662SScott Long device_printf(sc->dev, "can't alloc SG dma tag\n"); 3852aedd662SScott Long goto error; 3862aedd662SScott Long } 3872aedd662SScott Long /* create one command buffer until we know how many commands this card 3882aedd662SScott Long can handle */ 3892aedd662SScott Long sc->max_cmds = 1; 3902aedd662SScott Long ips_cmdqueue_init(sc); 3912aedd662SScott Long 3922aedd662SScott Long if(sc->ips_adapter_reinit(sc, 0)) 3932aedd662SScott Long goto error; 3942aedd662SScott Long 3957633e7f1SMartin Blapp /* initialize ffdc values */ 3967633e7f1SMartin Blapp microtime(&sc->ffdc_resettime); 3977633e7f1SMartin Blapp sc->ffdc_resetcount = 1; 3987633e7f1SMartin Blapp if ((i = ips_ffdc_reset(sc)) != 0) { 3997633e7f1SMartin Blapp device_printf(sc->dev, "failed to send ffdc reset to device (%d)\n", i); 4007633e7f1SMartin Blapp goto error; 4017633e7f1SMartin Blapp } 402dea4622dSScott Long if ((i = ips_get_adapter_info(sc)) != 0) { 403dea4622dSScott Long device_printf(sc->dev, "failed to get adapter configuration data from device (%d)\n", i); 404dea4622dSScott Long goto error; 405dea4622dSScott Long } 4067633e7f1SMartin Blapp ips_update_nvram(sc); /* no error check as failure doesn't matter */ 4077633e7f1SMartin Blapp if(sc->adapter_type > 0 && sc->adapter_type <= IPS_ADAPTER_MAX_T){ 4087633e7f1SMartin Blapp device_printf(sc->dev, "adapter type: %s\n", ips_adapter_name[sc->adapter_type]); 4097633e7f1SMartin Blapp } 410dea4622dSScott Long if ((i = ips_get_drive_info(sc)) != 0) { 411dea4622dSScott Long device_printf(sc->dev, "failed to get drive configuration data from device (%d)\n", i); 4122aedd662SScott Long goto error; 4132aedd662SScott Long } 4142aedd662SScott Long 4152aedd662SScott Long ips_cmdqueue_free(sc); 4162aedd662SScott Long if(sc->adapter_info.max_concurrent_cmds) 4172aedd662SScott Long sc->max_cmds = min(128, sc->adapter_info.max_concurrent_cmds); 4182aedd662SScott Long else 4192aedd662SScott Long sc->max_cmds = 32; 4202aedd662SScott Long if(ips_cmdqueue_init(sc)){ 4212aedd662SScott Long device_printf(sc->dev, "failed to initialize command buffers\n"); 4222aedd662SScott Long goto error; 4232aedd662SScott Long } 4242aedd662SScott Long sc->device_file = make_dev(&ips_cdevsw, device_get_unit(sc->dev), UID_ROOT, GID_OPERATOR, 4252aedd662SScott Long S_IRUSR | S_IWUSR, "ips%d", device_get_unit(sc->dev)); 4262aedd662SScott Long sc->device_file->si_drv1 = sc; 4272aedd662SScott Long ips_diskdev_init(sc); 428352176c8SJohn Baldwin callout_reset(&sc->timer, 10 * hz, ips_timeout, sc); 4292aedd662SScott Long return 0; 4302aedd662SScott Long 4312aedd662SScott Long error: 4322aedd662SScott Long ips_adapter_free(sc); 4332aedd662SScott Long return ENXIO; 4342aedd662SScott Long } 4352aedd662SScott Long 4362aedd662SScott Long /* see if we should reinitialize the card and wait for it to timeout or complete initialization */ 4372aedd662SScott Long int ips_morpheus_reinit(ips_softc_t *sc, int force) 4382aedd662SScott Long { 4392aedd662SScott Long u_int32_t tmp; 4402aedd662SScott Long int i; 4412aedd662SScott Long 4422aedd662SScott Long tmp = ips_read_4(sc, MORPHEUS_REG_OISR); 4432aedd662SScott Long if(!force && (ips_read_4(sc, MORPHEUS_REG_OMR0) >= IPS_POST1_OK) && 4442aedd662SScott Long (ips_read_4(sc, MORPHEUS_REG_OMR1) != 0xdeadbeef) && !tmp){ 4452aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_OIMR, 0); 4462aedd662SScott Long return 0; 4472aedd662SScott Long } 4482aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_OIMR, 0xff); 4492aedd662SScott Long ips_read_4(sc, MORPHEUS_REG_OIMR); 4502aedd662SScott Long 4512aedd662SScott Long device_printf(sc->dev, "resetting adapter, this may take up to 5 minutes\n"); 4522aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_IDR, 0x80000000); 4532aedd662SScott Long DELAY(5000000); 454f94dfeb4SScott Long ips_read_4(sc, MORPHEUS_REG_OIMR); 4552aedd662SScott Long 4562aedd662SScott Long tmp = ips_read_4(sc, MORPHEUS_REG_OISR); 4572aedd662SScott Long for(i = 0; i < 45 && !(tmp & MORPHEUS_BIT_POST1); i++){ 4582aedd662SScott Long DELAY(1000000); 4592aedd662SScott Long DEVICE_PRINTF(2, sc->dev, "post1: %d\n", i); 4602aedd662SScott Long tmp = ips_read_4(sc, MORPHEUS_REG_OISR); 4612aedd662SScott Long } 4622aedd662SScott Long if(tmp & MORPHEUS_BIT_POST1) 4632aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_OISR, MORPHEUS_BIT_POST1); 4642aedd662SScott Long 4652aedd662SScott Long if( i == 45 || ips_read_4(sc, MORPHEUS_REG_OMR0) < IPS_POST1_OK){ 4662aedd662SScott Long device_printf(sc->dev,"Adapter error during initialization.\n"); 4672aedd662SScott Long return 1; 4682aedd662SScott Long } 4692aedd662SScott Long for(i = 0; i < 240 && !(tmp & MORPHEUS_BIT_POST2); i++){ 4702aedd662SScott Long DELAY(1000000); 4712aedd662SScott Long DEVICE_PRINTF(2, sc->dev, "post2: %d\n", i); 4722aedd662SScott Long tmp = ips_read_4(sc, MORPHEUS_REG_OISR); 4732aedd662SScott Long } 4742aedd662SScott Long if(tmp & MORPHEUS_BIT_POST2) 4752aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_OISR, MORPHEUS_BIT_POST2); 4762aedd662SScott Long 4772aedd662SScott Long if(i == 240 || !ips_read_4(sc, MORPHEUS_REG_OMR1)){ 4782aedd662SScott Long device_printf(sc->dev, "adapter failed config check\n"); 4792aedd662SScott Long return 1; 4802aedd662SScott Long } 4812aedd662SScott Long ips_write_4(sc, MORPHEUS_REG_OIMR, 0); 4822aedd662SScott Long if(force && ips_clear_adapter(sc)){ 4832aedd662SScott Long device_printf(sc->dev, "adapter clear failed\n"); 4842aedd662SScott Long return 1; 4852aedd662SScott Long } 4862aedd662SScott Long return 0; 4872aedd662SScott Long } 4882aedd662SScott Long 4892aedd662SScott Long /* clean up so we can unload the driver. */ 4902aedd662SScott Long int ips_adapter_free(ips_softc_t *sc) 4912aedd662SScott Long { 4922aedd662SScott Long int error = 0; 4932aedd662SScott Long if(sc->state & IPS_DEV_OPEN) 4942aedd662SScott Long return EBUSY; 4952aedd662SScott Long if((error = ips_diskdev_free(sc))) 4962aedd662SScott Long return error; 4972aedd662SScott Long if(ips_cmdqueue_free(sc)){ 4982aedd662SScott Long device_printf(sc->dev, 4992aedd662SScott Long "trying to exit when command queue is not empty!\n"); 5002aedd662SScott Long return EBUSY; 5012aedd662SScott Long } 5022aedd662SScott Long DEVICE_PRINTF(1, sc->dev, "free\n"); 503352176c8SJohn Baldwin callout_drain(&sc->timer); 5042aedd662SScott Long 5052aedd662SScott Long if(sc->sg_dmatag) 5062aedd662SScott Long bus_dma_tag_destroy(sc->sg_dmatag); 5072aedd662SScott Long if(sc->command_dmatag) 5082aedd662SScott Long bus_dma_tag_destroy(sc->command_dmatag); 5092aedd662SScott Long if(sc->device_file) 5102aedd662SScott Long destroy_dev(sc->device_file); 5112aedd662SScott Long return 0; 5122aedd662SScott Long } 5132aedd662SScott Long 5147765040eSScott Long static __inline int ips_morpheus_check_intr(ips_softc_t *sc) 5152aedd662SScott Long { 5162aedd662SScott Long int cmdnumber; 5172aedd662SScott Long ips_cmd_status_t status; 5187765040eSScott Long ips_command_t *command; 5197765040eSScott Long int found = 0; 5207765040eSScott Long u_int32_t oisr; 5212aedd662SScott Long 5222aedd662SScott Long oisr = ips_read_4(sc, MORPHEUS_REG_OISR); 5237765040eSScott Long PRINTF(9, "interrupt registers out:%x\n", oisr); 5242aedd662SScott Long if(!(oisr & MORPHEUS_BIT_CMD_IRQ)){ 5252aedd662SScott Long DEVICE_PRINTF(2,sc->dev, "got a non-command irq\n"); 5267765040eSScott Long return (0); 5272aedd662SScott Long } 5282aedd662SScott Long while((status.value = ips_read_4(sc, MORPHEUS_REG_OQPR)) != 0xffffffff){ 5292aedd662SScott Long cmdnumber = status.fields.command_id; 5307765040eSScott Long command = &sc->commandarray[cmdnumber]; 5317765040eSScott Long command->status.value = status.value; 5327765040eSScott Long command->timeout = 0; 5337765040eSScott Long command->callback(command); 5342aedd662SScott Long 5357765040eSScott Long found = 1; 5362aedd662SScott Long } 5377765040eSScott Long return (found); 5387765040eSScott Long } 5397765040eSScott Long 5407765040eSScott Long void ips_morpheus_intr(void *void_sc) 5417765040eSScott Long { 5427765040eSScott Long ips_softc_t *sc = void_sc; 5437765040eSScott Long 5447765040eSScott Long mtx_lock(&sc->queue_mtx); 5457765040eSScott Long ips_morpheus_check_intr(sc); 54603a908f2SScott Long mtx_unlock(&sc->queue_mtx); 5477765040eSScott Long } 5487765040eSScott Long 5497765040eSScott Long void ips_morpheus_poll(ips_command_t *command) 5507765040eSScott Long { 5517765040eSScott Long uint32_t ts; 5527765040eSScott Long 5534ef63badSScott Long /* 5544ef63badSScott Long * Locks are not used here because this is only called during 5554ef63badSScott Long * crashdumps. 5564ef63badSScott Long */ 5577765040eSScott Long ts = time_second + command->timeout; 5587765040eSScott Long while ((command->timeout != 0) 5597765040eSScott Long && (ips_morpheus_check_intr(command->sc) == 0) 5607765040eSScott Long && (ts > time_second)) 5617765040eSScott Long DELAY(1000); 5622aedd662SScott Long } 5632aedd662SScott Long 5642aedd662SScott Long void ips_issue_morpheus_cmd(ips_command_t *command) 5652aedd662SScott Long { 5662aedd662SScott Long /* hmmm, is there a cleaner way to do this? */ 5672aedd662SScott Long if(command->sc->state & IPS_OFFLINE){ 5682eea7051SScott Long ips_set_error(command, EINVAL); 5692aedd662SScott Long command->callback(command); 5702aedd662SScott Long return; 5712aedd662SScott Long } 5722aedd662SScott Long command->timeout = 10; 5732aedd662SScott Long ips_write_4(command->sc, MORPHEUS_REG_IQPR, command->command_phys_addr); 5742aedd662SScott Long } 5752aedd662SScott Long 5762aedd662SScott Long static void ips_copperhead_queue_callback(void *queueptr, bus_dma_segment_t *segments,int segnum, int error) 5772aedd662SScott Long { 5782aedd662SScott Long ips_copper_queue_t *queue = queueptr; 5792aedd662SScott Long if(error){ 5802aedd662SScott Long return; 5812aedd662SScott Long } 5822aedd662SScott Long queue->base_phys_addr = segments[0].ds_addr; 5832aedd662SScott Long } 5842aedd662SScott Long 5852aedd662SScott Long static int ips_copperhead_queue_init(ips_softc_t *sc) 5862aedd662SScott Long { 5872aedd662SScott Long int error; 5882aedd662SScott Long bus_dma_tag_t dmatag; 58976fe16bbSHiren Panchasara bus_dmamap_t dmamap; 5902aedd662SScott Long if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, 5912aedd662SScott Long /* alignemnt */ 1, 5922aedd662SScott Long /* boundary */ 0, 5932aedd662SScott Long /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 5942aedd662SScott Long /* highaddr */ BUS_SPACE_MAXADDR, 5952aedd662SScott Long /* filter */ NULL, 5962aedd662SScott Long /* filterarg */ NULL, 5972aedd662SScott Long /* maxsize */ sizeof(ips_copper_queue_t), 5982aedd662SScott Long /* numsegs */ 1, 5992aedd662SScott Long /* maxsegsize*/ sizeof(ips_copper_queue_t), 6002aedd662SScott Long /* flags */ 0, 60103a908f2SScott Long /* lockfunc */ NULL, 60203a908f2SScott Long /* lockarg */ NULL, 6032aedd662SScott Long &dmatag) != 0) { 6042aedd662SScott Long device_printf(sc->dev, "can't alloc dma tag for statue queue\n"); 6052aedd662SScott Long error = ENOMEM; 60676fe16bbSHiren Panchasara return error; 6072aedd662SScott Long } 6082aedd662SScott Long if(bus_dmamem_alloc(dmatag, (void *)&(sc->copper_queue), 6092aedd662SScott Long BUS_DMA_NOWAIT, &dmamap)){ 6102aedd662SScott Long error = ENOMEM; 6112aedd662SScott Long goto exit; 6122aedd662SScott Long } 6132aedd662SScott Long bzero(sc->copper_queue, sizeof(ips_copper_queue_t)); 6142aedd662SScott Long sc->copper_queue->dmatag = dmatag; 6152aedd662SScott Long sc->copper_queue->dmamap = dmamap; 6162aedd662SScott Long sc->copper_queue->nextstatus = 1; 6172aedd662SScott Long bus_dmamap_load(dmatag, dmamap, 6182aedd662SScott Long &(sc->copper_queue->status[0]), IPS_MAX_CMD_NUM * 4, 6192aedd662SScott Long ips_copperhead_queue_callback, sc->copper_queue, 6202aedd662SScott Long BUS_DMA_NOWAIT); 6212aedd662SScott Long if(sc->copper_queue->base_phys_addr == 0){ 6222aedd662SScott Long error = ENOMEM; 6232aedd662SScott Long goto exit; 6242aedd662SScott Long } 6252aedd662SScott Long ips_write_4(sc, COPPER_REG_SQSR, sc->copper_queue->base_phys_addr); 6262aedd662SScott Long ips_write_4(sc, COPPER_REG_SQER, sc->copper_queue->base_phys_addr + 6272aedd662SScott Long IPS_MAX_CMD_NUM * 4); 6282aedd662SScott Long ips_write_4(sc, COPPER_REG_SQHR, sc->copper_queue->base_phys_addr + 4); 6292aedd662SScott Long ips_write_4(sc, COPPER_REG_SQTR, sc->copper_queue->base_phys_addr); 6302aedd662SScott Long 6312aedd662SScott Long 6322aedd662SScott Long return 0; 6332aedd662SScott Long exit: 63476fe16bbSHiren Panchasara if (sc->copper_queue != NULL) 6352aedd662SScott Long bus_dmamem_free(dmatag, sc->copper_queue, dmamap); 6362aedd662SScott Long bus_dma_tag_destroy(dmatag); 6372aedd662SScott Long return error; 6382aedd662SScott Long } 6392aedd662SScott Long 6402aedd662SScott Long /* see if we should reinitialize the card and wait for it to timeout or complete initialization FIXME */ 6412aedd662SScott Long int ips_copperhead_reinit(ips_softc_t *sc, int force) 6422aedd662SScott Long { 6432aedd662SScott Long int i, j; 6442aedd662SScott Long u_int32_t postcode = 0, configstatus = 0; 6452aedd662SScott Long ips_write_1(sc, COPPER_REG_SCPR, 0x80); 6462aedd662SScott Long ips_write_1(sc, COPPER_REG_SCPR, 0); 6472aedd662SScott Long device_printf(sc->dev, "reinitializing adapter, this could take several minutes.\n"); 6482aedd662SScott Long for(j = 0; j < 2; j++){ 6492aedd662SScott Long postcode <<= 8; 6502aedd662SScott Long for(i = 0; i < 45; i++){ 6512aedd662SScott Long if(ips_read_1(sc, COPPER_REG_HISR) & COPPER_GHI_BIT){ 6522aedd662SScott Long postcode |= ips_read_1(sc, COPPER_REG_ISPR); 6532aedd662SScott Long ips_write_1(sc, COPPER_REG_HISR, 6542aedd662SScott Long COPPER_GHI_BIT); 6552aedd662SScott Long break; 6562aedd662SScott Long } else 6572aedd662SScott Long DELAY(1000000); 6582aedd662SScott Long } 6592aedd662SScott Long if(i == 45) 6602aedd662SScott Long return 1; 6612aedd662SScott Long } 6622aedd662SScott Long for(j = 0; j < 2; j++){ 6632aedd662SScott Long configstatus <<= 8; 6642aedd662SScott Long for(i = 0; i < 240; i++){ 6652aedd662SScott Long if(ips_read_1(sc, COPPER_REG_HISR) & COPPER_GHI_BIT){ 6662aedd662SScott Long configstatus |= ips_read_1(sc, COPPER_REG_ISPR); 6672aedd662SScott Long ips_write_1(sc, COPPER_REG_HISR, 6682aedd662SScott Long COPPER_GHI_BIT); 6692aedd662SScott Long break; 6702aedd662SScott Long } else 6712aedd662SScott Long DELAY(1000000); 6722aedd662SScott Long } 6732aedd662SScott Long if(i == 240) 6742aedd662SScott Long return 1; 6752aedd662SScott Long } 6762aedd662SScott Long for(i = 0; i < 240; i++){ 6772aedd662SScott Long if(!(ips_read_1(sc, COPPER_REG_CBSP) & COPPER_OP_BIT)){ 6782aedd662SScott Long break; 6792aedd662SScott Long } else 6802aedd662SScott Long DELAY(1000000); 6812aedd662SScott Long } 6822aedd662SScott Long if(i == 240) 6832aedd662SScott Long return 1; 6842aedd662SScott Long ips_write_2(sc, COPPER_REG_CCCR, 0x1000 | COPPER_ILE_BIT); 6852aedd662SScott Long ips_write_1(sc, COPPER_REG_SCPR, COPPER_EBM_BIT); 6862aedd662SScott Long ips_copperhead_queue_init(sc); 6872aedd662SScott Long ips_write_1(sc, COPPER_REG_HISR, COPPER_GHI_BIT); 6882aedd662SScott Long i = ips_read_1(sc, COPPER_REG_SCPR); 6892aedd662SScott Long ips_write_1(sc, COPPER_REG_HISR, COPPER_EI_BIT); 6902aedd662SScott Long if(!configstatus){ 6912aedd662SScott Long device_printf(sc->dev, "adapter initialization failed\n"); 6922aedd662SScott Long return 1; 6932aedd662SScott Long } 6942aedd662SScott Long if(force && ips_clear_adapter(sc)){ 6952aedd662SScott Long device_printf(sc->dev, "adapter clear failed\n"); 6962aedd662SScott Long return 1; 6972aedd662SScott Long } 6982aedd662SScott Long return 0; 6992aedd662SScott Long } 7002aedd662SScott Long static u_int32_t ips_copperhead_cmd_status(ips_softc_t *sc) 7012aedd662SScott Long { 7022aedd662SScott Long u_int32_t value; 7032aedd662SScott Long int statnum = sc->copper_queue->nextstatus++; 7042aedd662SScott Long if(sc->copper_queue->nextstatus == IPS_MAX_CMD_NUM) 7052aedd662SScott Long sc->copper_queue->nextstatus = 0; 7062aedd662SScott Long value = sc->copper_queue->status[statnum]; 7072aedd662SScott Long ips_write_4(sc, COPPER_REG_SQTR, sc->copper_queue->base_phys_addr + 7082aedd662SScott Long 4 * statnum); 7092aedd662SScott Long return value; 7102aedd662SScott Long } 7112aedd662SScott Long 7122aedd662SScott Long 7132aedd662SScott Long void ips_copperhead_intr(void *void_sc) 7142aedd662SScott Long { 7152aedd662SScott Long ips_softc_t *sc = (ips_softc_t *)void_sc; 7162aedd662SScott Long int cmdnumber; 7172aedd662SScott Long ips_cmd_status_t status; 7182aedd662SScott Long 71903a908f2SScott Long mtx_lock(&sc->queue_mtx); 7202aedd662SScott Long while(ips_read_1(sc, COPPER_REG_HISR) & COPPER_SCE_BIT){ 7212aedd662SScott Long status.value = ips_copperhead_cmd_status(sc); 7222aedd662SScott Long cmdnumber = status.fields.command_id; 7232aedd662SScott Long sc->commandarray[cmdnumber].status.value = status.value; 7242aedd662SScott Long sc->commandarray[cmdnumber].timeout = 0; 7252aedd662SScott Long sc->commandarray[cmdnumber].callback(&(sc->commandarray[cmdnumber])); 7262aedd662SScott Long PRINTF(9, "ips: got command %d\n", cmdnumber); 7272aedd662SScott Long } 72803a908f2SScott Long mtx_unlock(&sc->queue_mtx); 7292aedd662SScott Long return; 7302aedd662SScott Long } 7312aedd662SScott Long 7322aedd662SScott Long void ips_issue_copperhead_cmd(ips_command_t *command) 7332aedd662SScott Long { 7342aedd662SScott Long int i; 7352aedd662SScott Long /* hmmm, is there a cleaner way to do this? */ 7362aedd662SScott Long if(command->sc->state & IPS_OFFLINE){ 7372eea7051SScott Long ips_set_error(command, EINVAL); 7382aedd662SScott Long command->callback(command); 7392aedd662SScott Long return; 7402aedd662SScott Long } 7412aedd662SScott Long command->timeout = 10; 7422aedd662SScott Long for(i = 0; ips_read_4(command->sc, COPPER_REG_CCCR) & COPPER_SEM_BIT; 7432aedd662SScott Long i++ ){ 7442aedd662SScott Long if( i == 20){ 7452aedd662SScott Long printf("sem bit still set, can't send a command\n"); 7462aedd662SScott Long return; 7472aedd662SScott Long } 7482aedd662SScott Long DELAY(500);/* need to do a delay here */ 7492aedd662SScott Long } 7502aedd662SScott Long ips_write_4(command->sc, COPPER_REG_CCSAR, command->command_phys_addr); 7512aedd662SScott Long ips_write_2(command->sc, COPPER_REG_CCCR, COPPER_CMD_START); 7522aedd662SScott Long } 7532aedd662SScott Long 7547765040eSScott Long void ips_copperhead_poll(ips_command_t *command) 7557765040eSScott Long { 7567765040eSScott Long 7577765040eSScott Long printf("ips: cmd polling not implemented for copperhead devices\n"); 7587765040eSScott Long } 759