12aedd662SScott Long /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
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>
31f94dfeb4SScott Long #include <dev/ips/ipsreg.h>
322aedd662SScott Long #include <dev/ips/ips.h>
332aedd662SScott Long #include <dev/ips/ips_ioctl.h>
34aad970f1SDavid E. O'Brien
ips_ioctl_finish(ips_command_t * command)352aedd662SScott Long static void ips_ioctl_finish(ips_command_t *command)
362aedd662SScott Long {
372aedd662SScott Long ips_ioctl_t *ioctl_cmd = command->arg;
382aedd662SScott Long if(ioctl_cmd->readwrite & IPS_IOCTL_READ){
392aedd662SScott Long bus_dmamap_sync(ioctl_cmd->dmatag, ioctl_cmd->dmamap,
402aedd662SScott Long BUS_DMASYNC_POSTREAD);
412aedd662SScott Long } else if(ioctl_cmd->readwrite & IPS_IOCTL_WRITE){
422aedd662SScott Long bus_dmamap_sync(ioctl_cmd->dmatag, ioctl_cmd->dmamap,
432aedd662SScott Long BUS_DMASYNC_POSTWRITE);
442aedd662SScott Long }
452aedd662SScott Long bus_dmamap_sync(command->sc->command_dmatag, command->command_dmamap,
462aedd662SScott Long BUS_DMASYNC_POSTWRITE);
472aedd662SScott Long bus_dmamap_unload(ioctl_cmd->dmatag, ioctl_cmd->dmamap);
482aedd662SScott Long ioctl_cmd->status.value = command->status.value;
492aedd662SScott Long ips_insert_free_cmd(command->sc, command);
502aedd662SScott Long }
512aedd662SScott Long
ips_ioctl_callback(void * cmdptr,bus_dma_segment_t * segments,int segnum,int error)522aedd662SScott Long static void ips_ioctl_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error)
532aedd662SScott Long {
542aedd662SScott Long ips_command_t *command = cmdptr;
552aedd662SScott Long ips_ioctl_t *ioctl_cmd = command->arg;
562aedd662SScott Long ips_generic_cmd *command_buffer = command->command_buffer;
572aedd662SScott Long if(error){
582eea7051SScott Long ips_set_error(command, error);
592aedd662SScott Long return;
602aedd662SScott Long }
612aedd662SScott Long command_buffer->id = command->id;
622aedd662SScott Long command_buffer->buffaddr = segments[0].ds_addr;
632aedd662SScott Long if(ioctl_cmd->readwrite & IPS_IOCTL_WRITE){
642aedd662SScott Long bus_dmamap_sync(ioctl_cmd->dmatag, ioctl_cmd->dmamap,
652aedd662SScott Long BUS_DMASYNC_PREWRITE);
662aedd662SScott Long } else if(ioctl_cmd->readwrite & IPS_IOCTL_READ){
672aedd662SScott Long bus_dmamap_sync(ioctl_cmd->dmatag, ioctl_cmd->dmamap,
682aedd662SScott Long BUS_DMASYNC_PREREAD);
692aedd662SScott Long }
702aedd662SScott Long bus_dmamap_sync(command->sc->command_dmatag, command->command_dmamap,
712aedd662SScott Long BUS_DMASYNC_PREWRITE);
722aedd662SScott Long command->sc->ips_issue_cmd(command);
732aedd662SScott Long }
ips_ioctl_start(ips_command_t * command)742aedd662SScott Long static int ips_ioctl_start(ips_command_t *command)
752aedd662SScott Long {
762aedd662SScott Long ips_ioctl_t *ioctl_cmd = command->arg;
772aedd662SScott Long memcpy(command->command_buffer, ioctl_cmd->command_buffer,
782aedd662SScott Long sizeof(ips_generic_cmd));
792aedd662SScott Long command->callback = ips_ioctl_finish;
802aedd662SScott Long bus_dmamap_load(ioctl_cmd->dmatag, ioctl_cmd->dmamap,
812aedd662SScott Long ioctl_cmd->data_buffer,ioctl_cmd->datasize,
822aedd662SScott Long ips_ioctl_callback, command, 0);
832aedd662SScott Long return 0;
842aedd662SScott Long }
852aedd662SScott Long
ips_ioctl_cmd(ips_softc_t * sc,ips_ioctl_t * ioctl_cmd,ips_user_request * user_request)862aedd662SScott Long static int ips_ioctl_cmd(ips_softc_t *sc, ips_ioctl_t *ioctl_cmd, ips_user_request *user_request)
872aedd662SScott Long {
8803a908f2SScott Long ips_command_t *command;
892aedd662SScott Long int error = EINVAL;
9025371920SPoul-Henning Kamp
912aedd662SScott Long if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag,
922aedd662SScott Long /* alignment */ 1,
932aedd662SScott Long /* boundary */ 0,
942aedd662SScott Long /* lowaddr */ BUS_SPACE_MAXADDR_32BIT,
952aedd662SScott Long /* highaddr */ BUS_SPACE_MAXADDR,
962aedd662SScott Long /* filter */ NULL,
972aedd662SScott Long /* filterarg */ NULL,
982aedd662SScott Long /* maxsize */ ioctl_cmd->datasize,
992aedd662SScott Long /* numsegs */ 1,
1002aedd662SScott Long /* maxsegsize*/ ioctl_cmd->datasize,
1012aedd662SScott Long /* flags */ 0,
10203a908f2SScott Long /* lockfunc */ NULL,
10303a908f2SScott Long /* lockarg */ NULL,
1042aedd662SScott Long &ioctl_cmd->dmatag) != 0) {
1052aedd662SScott Long return ENOMEM;
1062aedd662SScott Long }
1072aedd662SScott Long if(bus_dmamem_alloc(ioctl_cmd->dmatag, &ioctl_cmd->data_buffer,
1082aedd662SScott Long 0, &ioctl_cmd->dmamap)){
1092aedd662SScott Long error = ENOMEM;
1102aedd662SScott Long goto exit;
1112aedd662SScott Long }
1122aedd662SScott Long if(copyin(user_request->data_buffer,ioctl_cmd->data_buffer,
1132aedd662SScott Long ioctl_cmd->datasize))
1142aedd662SScott Long goto exit;
1152aedd662SScott Long ioctl_cmd->status.value = 0xffffffff;
11603a908f2SScott Long mtx_lock(&sc->queue_mtx);
11703a908f2SScott Long if((error = ips_get_free_cmd(sc, &command, 0)) > 0){
1182aedd662SScott Long error = ENOMEM;
11903a908f2SScott Long mtx_unlock(&sc->queue_mtx);
1202aedd662SScott Long goto exit;
1212aedd662SScott Long }
12203a908f2SScott Long command->arg = ioctl_cmd;
12303a908f2SScott Long ips_ioctl_start(command);
1242aedd662SScott Long while( ioctl_cmd->status.value == 0xffffffff)
12503a908f2SScott Long msleep(ioctl_cmd, &sc->queue_mtx, 0, "ips", hz/10);
1262eea7051SScott Long if(COMMAND_ERROR(ioctl_cmd))
1272aedd662SScott Long error = EIO;
1282aedd662SScott Long else
1292aedd662SScott Long error = 0;
13003a908f2SScott Long mtx_unlock(&sc->queue_mtx);
1312aedd662SScott Long if(copyout(ioctl_cmd->data_buffer, user_request->data_buffer,
1322aedd662SScott Long ioctl_cmd->datasize))
1332aedd662SScott Long error = EINVAL;
1342eea7051SScott Long mtx_lock(&sc->queue_mtx);
1352eea7051SScott Long ips_insert_free_cmd(sc, command);
1362eea7051SScott Long mtx_unlock(&sc->queue_mtx);
1372eea7051SScott Long
1382aedd662SScott Long exit: bus_dmamem_free(ioctl_cmd->dmatag, ioctl_cmd->data_buffer,
1392aedd662SScott Long ioctl_cmd->dmamap);
1402aedd662SScott Long bus_dma_tag_destroy(ioctl_cmd->dmatag);
1412aedd662SScott Long return error;
1422aedd662SScott Long }
1432aedd662SScott Long
1442aedd662SScott Long
ips_ioctl_request(ips_softc_t * sc,u_long ioctl_request,caddr_t addr,int32_t flags)1452aedd662SScott Long int ips_ioctl_request(ips_softc_t *sc, u_long ioctl_request, caddr_t addr, int32_t flags){
1462aedd662SScott Long int error = EINVAL;
1472aedd662SScott Long ips_ioctl_t *ioctl_cmd;
1482aedd662SScott Long ips_user_request *user_request;
1492aedd662SScott Long switch(ioctl_request){
1502aedd662SScott Long case IPS_USER_CMD:
1512aedd662SScott Long user_request = (ips_user_request *)addr;
152dd83a01eSScott Long ioctl_cmd = malloc(sizeof(ips_ioctl_t), M_IPSBUF, M_WAITOK);
1532aedd662SScott Long ioctl_cmd->command_buffer = malloc(sizeof(ips_generic_cmd),
154dd83a01eSScott Long M_IPSBUF, M_WAITOK);
1552aedd662SScott Long if(copyin(user_request->command_buffer,
1562aedd662SScott Long ioctl_cmd->command_buffer, sizeof(ips_generic_cmd))){
157dd83a01eSScott Long free(ioctl_cmd->command_buffer, M_IPSBUF);
158dd83a01eSScott Long free(ioctl_cmd, M_IPSBUF);
1592aedd662SScott Long break;
1602aedd662SScott Long }
1612aedd662SScott Long ioctl_cmd->readwrite = IPS_IOCTL_READ | IPS_IOCTL_WRITE;
1622aedd662SScott Long ioctl_cmd->datasize = IPS_IOCTL_BUFFER_SIZE;
1632aedd662SScott Long error = ips_ioctl_cmd(sc, ioctl_cmd, user_request);
164dd83a01eSScott Long free(ioctl_cmd->command_buffer, M_IPSBUF);
165dd83a01eSScott Long free(ioctl_cmd, M_IPSBUF);
1662aedd662SScott Long break;
1672aedd662SScott Long }
1682aedd662SScott Long
1692aedd662SScott Long return error;
1702aedd662SScott Long }
171