xref: /freebsd-src/sys/dev/ips/ips_ioctl.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
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