/* clean up so we can unload the driver. */ int ips_adapter_free(ips_softc_t *sc) { int error = 0; intrmask_t mask; if(sc->state & IPS_DEV_OPEN) return EBUSY; if((error = ips_diskdev_free(sc))) return error; if(ips_cmdqueue_free(sc)){ device_printf(sc->dev, "trying to exit when command queue is not empty!\n"); return EBUSY; } DEVICE_PRINTF(1, sc->dev, "free\n"); mask = splbio(); untimeout(ips_timeout, sc, sc->timer); splx(mask); if (mtx_initialized(&sc->cmd_mtx)) mtx_destroy(&sc->cmd_mtx); if(sc->sg_dmatag) bus_dma_tag_destroy(sc->sg_dmatag); if(sc->command_dmatag) bus_dma_tag_destroy(sc->command_dmatag); if(sc->device_file) destroy_dev(sc->device_file); return 0; }
/* places all ips command structs on the free command queue. No locking as if someone else tries * to access this during init, we have bigger problems */ static __inline__ int ips_cmdqueue_init(ips_softc_t *sc) { int i; ips_command_t *command; SLIST_INIT(&sc->free_cmd_list); STAILQ_INIT(&sc->cmd_wait_list); for(i = 0; i < sc->max_cmds; i++){ sc->commandarray[i].id = i; sc->commandarray[i].sc = sc; SLIST_INSERT_HEAD(&sc->free_cmd_list, &sc->commandarray[i], next); } for(i = 0; i < sc->max_cmds; i++){ command = &sc->commandarray[i]; if(bus_dmamem_alloc(sc->command_dmatag,&command->command_buffer, BUS_DMA_NOWAIT, &command->command_dmamap)) goto error; bus_dmamap_load(sc->command_dmatag, command->command_dmamap, command->command_buffer,IPS_COMMAND_LEN, ips_cmd_dmaload, command, BUS_DMA_NOWAIT); if(!command->command_phys_addr){ bus_dmamem_free(sc->command_dmatag, command->command_buffer, command->command_dmamap); goto error; } } sc->state &= ~IPS_OFFLINE; return 0; error: ips_cmdqueue_free(sc); return ENOMEM; }
/* places all ips command structs on the free command queue. No locking as if someone else tries * to access this during init, we have bigger problems */ static int ips_cmdqueue_init(ips_softc_t *sc) { int i; ips_command_t *command; sc->commandarray = (ips_command_t *)malloc(sizeof(ips_command_t) * sc->max_cmds, M_DEVBUF, M_NOWAIT|M_ZERO); if (sc->commandarray == NULL) return (ENOMEM); SLIST_INIT(&sc->free_cmd_list); for(i = 0; i < sc->max_cmds; i++){ command = &sc->commandarray[i]; command->id = i; command->sc = sc; if(bus_dmamem_alloc(sc->command_dmatag,&command->command_buffer, BUS_DMA_NOWAIT, &command->command_dmamap)) goto error; bus_dmamap_load(sc->command_dmatag, command->command_dmamap, command->command_buffer,IPS_COMMAND_LEN, ips_cmd_dmaload, command, BUS_DMA_NOWAIT); if(!command->command_phys_addr){ bus_dmamem_free(sc->command_dmatag, command->command_buffer, command->command_dmamap); goto error; } if (i != 0) { command->data_dmatag = sc->sg_dmatag; if (bus_dmamap_create(command->data_dmatag, 0, &command->data_dmamap)) goto error; SLIST_INSERT_HEAD(&sc->free_cmd_list, command, next); } else sc->staticcmd = command; } sc->state &= ~IPS_OFFLINE; return 0; error: ips_cmdqueue_free(sc); return ENOMEM; }
/* clean up so we can unload the driver. */ int ips_adapter_free(ips_softc_t *sc) { int error = 0; if(sc->state & IPS_DEV_OPEN) return EBUSY; if((error = ips_diskdev_free(sc))) return error; if(ips_cmdqueue_free(sc)){ device_printf(sc->dev, "trying to exit when command queue is not empty!\n"); return EBUSY; } DEVICE_PRINTF(1, sc->dev, "free\n"); callout_drain(&sc->timer); if(sc->sg_dmatag) bus_dma_tag_destroy(sc->sg_dmatag); if(sc->command_dmatag) bus_dma_tag_destroy(sc->command_dmatag); if(sc->device_file) destroy_dev(sc->device_file); return 0; }
/* check card and initialize it */ int ips_adapter_init(ips_softc_t *sc) { int i; DEVICE_PRINTF(1,sc->dev, "initializing\n"); if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, /* alignemnt */ 1, /* boundary */ 0, /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, /* highaddr */ BUS_SPACE_MAXADDR, /* filter */ NULL, /* filterarg */ NULL, /* maxsize */ IPS_COMMAND_LEN + IPS_MAX_SG_LEN, /* numsegs */ 1, /* maxsegsize*/ IPS_COMMAND_LEN + IPS_MAX_SG_LEN, /* flags */ 0, /* lockfunc */ NULL, /* lockarg */ NULL, &sc->command_dmatag) != 0) { device_printf(sc->dev, "can't alloc command dma tag\n"); goto error; } if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, /* alignemnt */ 1, /* boundary */ 0, /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, /* highaddr */ BUS_SPACE_MAXADDR, /* filter */ NULL, /* filterarg */ NULL, /* maxsize */ IPS_MAX_IOBUF_SIZE, /* numsegs */ IPS_MAX_SG_ELEMENTS, /* maxsegsize*/ IPS_MAX_IOBUF_SIZE, /* flags */ 0, /* lockfunc */ busdma_lock_mutex, /* lockarg */ &sc->queue_mtx, &sc->sg_dmatag) != 0) { device_printf(sc->dev, "can't alloc SG dma tag\n"); goto error; } /* create one command buffer until we know how many commands this card can handle */ sc->max_cmds = 1; ips_cmdqueue_init(sc); if(sc->ips_adapter_reinit(sc, 0)) goto error; /* initialize ffdc values */ microtime(&sc->ffdc_resettime); sc->ffdc_resetcount = 1; if ((i = ips_ffdc_reset(sc)) != 0) { device_printf(sc->dev, "failed to send ffdc reset to device (%d)\n", i); goto error; } if ((i = ips_get_adapter_info(sc)) != 0) { device_printf(sc->dev, "failed to get adapter configuration data from device (%d)\n", i); goto error; } ips_update_nvram(sc); /* no error check as failure doesn't matter */ if(sc->adapter_type > 0 && sc->adapter_type <= IPS_ADAPTER_MAX_T){ device_printf(sc->dev, "adapter type: %s\n", ips_adapter_name[sc->adapter_type]); } if ((i = ips_get_drive_info(sc)) != 0) { device_printf(sc->dev, "failed to get drive configuration data from device (%d)\n", i); goto error; } ips_cmdqueue_free(sc); if(sc->adapter_info.max_concurrent_cmds) sc->max_cmds = min(128, sc->adapter_info.max_concurrent_cmds); else sc->max_cmds = 32; if(ips_cmdqueue_init(sc)){ device_printf(sc->dev, "failed to initialize command buffers\n"); goto error; } sc->device_file = make_dev(&ips_cdevsw, device_get_unit(sc->dev), UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR, "ips%d", device_get_unit(sc->dev)); sc->device_file->si_drv1 = sc; ips_diskdev_init(sc); callout_reset(&sc->timer, 10 * hz, ips_timeout, sc); return 0; error: ips_adapter_free(sc); return ENXIO; }
/* check card and initialize it */ int ips_adapter_init(ips_softc_t *sc) { DEVICE_PRINTF(1,sc->dev, "initializing\n"); if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, /* alignemnt */ 1, /* boundary */ 0, /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, /* highaddr */ BUS_SPACE_MAXADDR, /* filter */ NULL, /* filterarg */ NULL, /* maxsize */ IPS_COMMAND_LEN + IPS_MAX_SG_LEN, /* numsegs */ 1, /* maxsegsize*/ IPS_COMMAND_LEN + IPS_MAX_SG_LEN, /* flags */ 0, &sc->command_dmatag) != 0) { device_printf(sc->dev, "can't alloc command dma tag\n"); goto error; } if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag, /* alignemnt */ 1, /* boundary */ 0, /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, /* highaddr */ BUS_SPACE_MAXADDR, /* filter */ NULL, /* filterarg */ NULL, /* maxsize */ IPS_MAX_IOBUF_SIZE, /* numsegs */ IPS_MAX_SG_ELEMENTS, /* maxsegsize*/ IPS_MAX_IOBUF_SIZE, /* flags */ 0, &sc->sg_dmatag) != 0) { device_printf(sc->dev, "can't alloc SG dma tag\n"); goto error; } /* create one command buffer until we know how many commands this card can handle */ sc->max_cmds = 1; ips_cmdqueue_init(sc); if(sc->ips_adapter_reinit(sc, 0)) goto error; mtx_init(&sc->cmd_mtx, "ips command mutex", NULL, MTX_DEF); if(ips_get_adapter_info(sc) || ips_get_drive_info(sc)){ device_printf(sc->dev, "failed to get configuration data from device\n"); goto error; } ips_update_nvram(sc); /* no error check as failure doesn't matter */ ips_cmdqueue_free(sc); if(sc->adapter_info.max_concurrent_cmds) sc->max_cmds = min(128, sc->adapter_info.max_concurrent_cmds); else sc->max_cmds = 32; if(ips_cmdqueue_init(sc)){ device_printf(sc->dev, "failed to initialize command buffers\n"); goto error; } sc->device_file = make_dev(&ips_cdevsw, device_get_unit(sc->dev), UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR, "ips%d", device_get_unit(sc->dev)); sc->device_file->si_drv1 = sc; ips_diskdev_init(sc); sc->timer = timeout(ips_timeout, sc, 10*hz); return 0; error: ips_adapter_free(sc); return ENXIO; }