xref: /freebsd/sys/dev/ips/ips.c (revision dea4622d59e44daa47a9084e53198a730eefaab9)
12aedd662SScott Long /*-
22aedd662SScott Long  * Copyright (c) 2002 Adaptec Inc.
32aedd662SScott Long  * All rights reserved.
42aedd662SScott Long  *
52aedd662SScott Long  * Written by: David Jeffery
62aedd662SScott Long  *
72aedd662SScott Long  * Redistribution and use in source and binary forms, with or without
82aedd662SScott Long  * modification, are permitted provided that the following conditions
92aedd662SScott Long  * are met:
102aedd662SScott Long  * 1. Redistributions of source code must retain the above copyright
112aedd662SScott Long  *    notice, this list of conditions and the following disclaimer.
122aedd662SScott Long  * 2. Redistributions in binary form must reproduce the above copyright
132aedd662SScott Long  *    notice, this list of conditions and the following disclaimer in the
142aedd662SScott Long  *    documentation and/or other materials provided with the distribution.
152aedd662SScott Long  *
162aedd662SScott Long  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
172aedd662SScott Long  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
182aedd662SScott Long  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
192aedd662SScott Long  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
202aedd662SScott Long  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
212aedd662SScott Long  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
222aedd662SScott Long  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
232aedd662SScott Long  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
242aedd662SScott Long  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
252aedd662SScott Long  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
262aedd662SScott Long  * SUCH DAMAGE.
272aedd662SScott Long  *
282aedd662SScott Long  * $FreeBSD$
292aedd662SScott Long  */
302aedd662SScott Long 
312aedd662SScott Long 
322aedd662SScott Long #include <dev/ips/ips.h>
332aedd662SScott Long #include <sys/stat.h>
342aedd662SScott Long #include <sys/time.h>
352aedd662SScott Long #include <machine/clock.h>
362aedd662SScott Long 
372aedd662SScott Long static d_open_t ips_open;
382aedd662SScott Long static d_close_t ips_close;
392aedd662SScott Long static d_ioctl_t ips_ioctl;
402aedd662SScott Long 
412aedd662SScott Long #define IPS_CDEV_MAJOR 175
422aedd662SScott Long static struct cdevsw ips_cdevsw = {
432aedd662SScott Long 	.d_open = ips_open,
442aedd662SScott Long 	.d_close = ips_close,
452aedd662SScott Long 	.d_ioctl = ips_ioctl,
462aedd662SScott Long 	.d_name = "ips",
472aedd662SScott Long 	.d_maj = IPS_CDEV_MAJOR,
482aedd662SScott Long };
492aedd662SScott Long 
502aedd662SScott Long 
512aedd662SScott Long static int ips_open(dev_t dev, int flags, int fmt, struct thread *td)
522aedd662SScott Long {
532aedd662SScott Long 	ips_softc_t *sc = dev->si_drv1;
542aedd662SScott Long 	sc->state |= IPS_DEV_OPEN;
552aedd662SScott Long         return 0;
562aedd662SScott Long }
572aedd662SScott Long 
582aedd662SScott Long static int ips_close(dev_t dev, int flags, int fmt, struct thread *td)
592aedd662SScott Long {
602aedd662SScott Long 	ips_softc_t *sc = dev->si_drv1;
612aedd662SScott Long 	sc->state &= ~IPS_DEV_OPEN;
622aedd662SScott Long 
632aedd662SScott Long         return 0;
642aedd662SScott Long }
652aedd662SScott Long 
662aedd662SScott Long static int ips_ioctl(dev_t dev, u_long command, caddr_t addr, int32_t flags, struct thread *td)
672aedd662SScott Long {
682aedd662SScott Long 	ips_softc_t *sc;
692aedd662SScott Long 
702aedd662SScott Long 	sc = dev->si_drv1;
712aedd662SScott Long 	return ips_ioctl_request(sc, command, addr, flags);
722aedd662SScott Long }
732aedd662SScott Long 
742aedd662SScott Long static void ips_cmd_dmaload(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error)
752aedd662SScott Long {
762aedd662SScott Long 	ips_command_t *command = cmdptr;
772aedd662SScott Long 	PRINTF(10, "ips: in ips_cmd_dmaload\n");
782aedd662SScott Long 	if(!error)
792aedd662SScott Long 		command->command_phys_addr = segments[0].ds_addr;
802aedd662SScott Long 
812aedd662SScott Long }
822aedd662SScott Long 
832aedd662SScott Long /* is locking needed? what locking guarentees are there on removal? */
842aedd662SScott Long static __inline__ int ips_cmdqueue_free(ips_softc_t *sc)
852aedd662SScott Long {
862aedd662SScott Long 	int i, error = -1;
872aedd662SScott Long 	intrmask_t mask = splbio();
882aedd662SScott Long 	if(!sc->used_commands){
892aedd662SScott Long 		for(i = 0; i < sc->max_cmds; i++){
902aedd662SScott Long 			if(!(sc->commandarray[i].command_phys_addr))
912aedd662SScott Long 				continue;
922aedd662SScott Long 			bus_dmamap_unload(sc->command_dmatag,
932aedd662SScott Long 					  sc->commandarray[i].command_dmamap);
942aedd662SScott Long 			bus_dmamem_free(sc->command_dmatag,
952aedd662SScott Long 					sc->commandarray[i].command_buffer,
962aedd662SScott Long 					sc->commandarray[i].command_dmamap);
972aedd662SScott Long 		}
982aedd662SScott Long 		error = 0;
992aedd662SScott Long 		sc->state |= IPS_OFFLINE;
1002aedd662SScott Long 	}
1012aedd662SScott Long 	splx(mask);
1022aedd662SScott Long 	return error;
1032aedd662SScott Long }
1042aedd662SScott Long 
1052aedd662SScott Long /* places all ips command structs on the free command queue.  No locking as if someone else tries
1062aedd662SScott Long  * to access this during init, we have bigger problems */
1072aedd662SScott Long static __inline__ int ips_cmdqueue_init(ips_softc_t *sc)
1082aedd662SScott Long {
1092aedd662SScott Long 	int i;
1102aedd662SScott Long 	ips_command_t *command;
1112aedd662SScott Long 	SLIST_INIT(&sc->free_cmd_list);
1122aedd662SScott Long 	STAILQ_INIT(&sc->cmd_wait_list);
1132aedd662SScott Long 	for(i = 0; i < sc->max_cmds; i++){
1142aedd662SScott Long 		sc->commandarray[i].id = i;
1152aedd662SScott Long 		sc->commandarray[i].sc = sc;
1162aedd662SScott Long 		SLIST_INSERT_HEAD(&sc->free_cmd_list, &sc->commandarray[i],
1172aedd662SScott Long 				  next);
1182aedd662SScott Long 	}
1192aedd662SScott Long 	for(i = 0; i < sc->max_cmds; i++){
1202aedd662SScott Long 		command = &sc->commandarray[i];
1212aedd662SScott Long 		if(bus_dmamem_alloc(sc->command_dmatag,&command->command_buffer,
1222aedd662SScott Long 		    BUS_DMA_NOWAIT, &command->command_dmamap))
1232aedd662SScott Long 			goto error;
1242aedd662SScott Long 		bus_dmamap_load(sc->command_dmatag, command->command_dmamap,
1252aedd662SScott Long 				command->command_buffer,IPS_COMMAND_LEN,
1262aedd662SScott Long 				ips_cmd_dmaload, command, BUS_DMA_NOWAIT);
1272aedd662SScott Long 		if(!command->command_phys_addr){
1282aedd662SScott Long 			bus_dmamem_free(sc->command_dmatag,
1292aedd662SScott Long 			    command->command_buffer, command->command_dmamap);
1302aedd662SScott Long 			goto error;
1312aedd662SScott Long 		}
1322aedd662SScott Long 	}
1332aedd662SScott Long 	sc->state &= ~IPS_OFFLINE;
1342aedd662SScott Long 	return 0;
1352aedd662SScott Long error:
1362aedd662SScott Long 		ips_cmdqueue_free(sc);
1372aedd662SScott Long 		return ENOMEM;
1382aedd662SScott Long }
1392aedd662SScott Long 
1402aedd662SScott Long static int ips_add_waiting_command(ips_softc_t *sc, int (*callback)(ips_command_t *), void *data, unsigned long flags)
1412aedd662SScott Long {
1422aedd662SScott Long 	intrmask_t mask;
1432aedd662SScott Long 	ips_command_t *command;
1442aedd662SScott Long 	ips_wait_list_t *waiter;
1452aedd662SScott Long 	unsigned long memflags = 0;
1462aedd662SScott Long 	if(IPS_NOWAIT_FLAG & flags)
1472aedd662SScott Long 		memflags = M_NOWAIT;
1482aedd662SScott Long 	waiter = malloc(sizeof(ips_wait_list_t), M_DEVBUF, memflags);
1492aedd662SScott Long 	if(!waiter)
1502aedd662SScott Long 		return ENOMEM;
1512aedd662SScott Long 	mask = splbio();
1522aedd662SScott Long 	if(sc->state & IPS_OFFLINE){
1532aedd662SScott Long 		splx(mask);
1542aedd662SScott Long 		return EIO;
1552aedd662SScott Long 	}
1562aedd662SScott Long 	command = SLIST_FIRST(&sc->free_cmd_list);
1572aedd662SScott Long 	if(command && !(sc->state & IPS_TIMEOUT)){
1582aedd662SScott Long 		SLIST_REMOVE_HEAD(&sc->free_cmd_list, next);
1592aedd662SScott Long 		(sc->used_commands)++;
1602aedd662SScott Long 		splx(mask);
1612aedd662SScott Long 		clear_ips_command(command);
1622aedd662SScott Long 		bzero(command->command_buffer, IPS_COMMAND_LEN);
1632aedd662SScott Long 		free(waiter, M_DEVBUF);
1642aedd662SScott Long 		command->arg = data;
1652aedd662SScott Long 		return callback(command);
1662aedd662SScott Long 	}
1672aedd662SScott Long 	DEVICE_PRINTF(1, sc->dev, "adding command to the wait queue\n");
1682aedd662SScott Long 	waiter->callback = callback;
1692aedd662SScott Long 	waiter->data = data;
1702aedd662SScott Long 	STAILQ_INSERT_TAIL(&sc->cmd_wait_list, waiter, next);
1712aedd662SScott Long 	splx(mask);
1722aedd662SScott Long 	return 0;
1732aedd662SScott Long }
1742aedd662SScott Long 
1752aedd662SScott Long static void ips_run_waiting_command(ips_softc_t *sc)
1762aedd662SScott Long {
1772aedd662SScott Long 	ips_wait_list_t *waiter;
1782aedd662SScott Long 	ips_command_t	*command;
1792aedd662SScott Long 	int (*callback)(ips_command_t*);
1802aedd662SScott Long 	intrmask_t mask;
1812aedd662SScott Long 
1822aedd662SScott Long 	mask = splbio();
1832aedd662SScott Long 	waiter = STAILQ_FIRST(&sc->cmd_wait_list);
1842aedd662SScott Long 	command = SLIST_FIRST(&sc->free_cmd_list);
1852aedd662SScott Long 	if(!waiter || !command){
1862aedd662SScott Long 		splx(mask);
1872aedd662SScott Long 		return;
1882aedd662SScott Long 	}
1892aedd662SScott Long 	DEVICE_PRINTF(1, sc->dev, "removing command from wait queue\n");
1902aedd662SScott Long 	SLIST_REMOVE_HEAD(&sc->free_cmd_list, next);
1912aedd662SScott Long 	STAILQ_REMOVE_HEAD(&sc->cmd_wait_list, next);
1922aedd662SScott Long 	(sc->used_commands)++;
1932aedd662SScott Long 	splx(mask);
1942aedd662SScott Long 	clear_ips_command(command);
1952aedd662SScott Long 	bzero(command->command_buffer, IPS_COMMAND_LEN);
1962aedd662SScott Long 	command->arg = waiter->data;
1972aedd662SScott Long 	callback = waiter->callback;
1982aedd662SScott Long 	free(waiter, M_DEVBUF);
1992aedd662SScott Long 	callback(command);
2002aedd662SScott Long 	return;
2012aedd662SScott Long }
2022aedd662SScott Long /* returns a free command struct if one is available.
2032aedd662SScott Long  * It also blanks out anything that may be a wild pointer/value.
2042aedd662SScott Long  * Also, command buffers are not freed.  They are
2052aedd662SScott Long  * small so they are saved and kept dmamapped and loaded.
2062aedd662SScott Long  */
2072aedd662SScott Long int ips_get_free_cmd(ips_softc_t *sc, int (*callback)(ips_command_t *), void *data, unsigned long flags)
2082aedd662SScott Long {
2092aedd662SScott Long 	intrmask_t mask;
2102aedd662SScott Long 	ips_command_t *command;
2112aedd662SScott Long 	mask = splbio();
2122aedd662SScott Long 
2132aedd662SScott Long 	if(sc->state & IPS_OFFLINE){
2142aedd662SScott Long 		splx(mask);
2152aedd662SScott Long 		return EIO;
2162aedd662SScott Long 	}
2172aedd662SScott Long 	command = SLIST_FIRST(&sc->free_cmd_list);
2182aedd662SScott Long 	if(!command || (sc->state & IPS_TIMEOUT)){
2192aedd662SScott Long 		splx(mask);
2202aedd662SScott Long 		if(flags & IPS_NOWAIT_FLAG)
2212aedd662SScott Long 			return EAGAIN;
2222aedd662SScott Long 		return ips_add_waiting_command(sc, callback, data, flags);
2232aedd662SScott Long 	}
2242aedd662SScott Long 	SLIST_REMOVE_HEAD(&sc->free_cmd_list, next);
2252aedd662SScott Long 	(sc->used_commands)++;
2262aedd662SScott Long 	splx(mask);
2272aedd662SScott Long 	clear_ips_command(command);
2282aedd662SScott Long 	bzero(command->command_buffer, IPS_COMMAND_LEN);
2292aedd662SScott Long 	command->arg = data;
2302aedd662SScott Long 	return callback(command);
2312aedd662SScott Long }
2322aedd662SScott Long 
2332aedd662SScott Long /* adds a command back to the free command queue */
2342aedd662SScott Long void ips_insert_free_cmd(ips_softc_t *sc, ips_command_t *command)
2352aedd662SScott Long {
2362aedd662SScott Long 	intrmask_t mask;
2372aedd662SScott Long 	mask = splbio();
2382aedd662SScott Long 	SLIST_INSERT_HEAD(&sc->free_cmd_list, command, next);
2392aedd662SScott Long 	(sc->used_commands)--;
2402aedd662SScott Long 	splx(mask);
2412aedd662SScott Long 	if(!(sc->state & IPS_TIMEOUT))
2422aedd662SScott Long 		ips_run_waiting_command(sc);
2432aedd662SScott Long }
2442aedd662SScott Long 
2452aedd662SScott Long static int ips_diskdev_init(ips_softc_t *sc)
2462aedd662SScott Long {
2472aedd662SScott Long 	int i;
2482aedd662SScott Long 	for(i=0; i < IPS_MAX_NUM_DRIVES; i++){
2492aedd662SScott Long 		if(sc->drives[i].state & IPS_LD_OKAY){
2502aedd662SScott Long 			sc->diskdev[i] = device_add_child(sc->dev, NULL, -1);
2512aedd662SScott Long 			device_set_ivars(sc->diskdev[i],(void *) i);
2522aedd662SScott Long 		}
2532aedd662SScott Long 	}
2542aedd662SScott Long 	if(bus_generic_attach(sc->dev)){
2552aedd662SScott Long 		device_printf(sc->dev, "Attaching bus failed\n");
2562aedd662SScott Long 	}
2572aedd662SScott Long 	return 0;
2582aedd662SScott Long }
2592aedd662SScott Long 
2602aedd662SScott Long static int ips_diskdev_free(ips_softc_t *sc)
2612aedd662SScott Long {
2622aedd662SScott Long 	int i;
2632aedd662SScott Long 	int error = 0;
2642aedd662SScott Long 	for(i = 0; i < IPS_MAX_NUM_DRIVES; i++){
2652aedd662SScott Long 		if(sc->diskdev[i])
2662aedd662SScott Long 			error = device_delete_child(sc->dev, sc->diskdev[i]);
2672aedd662SScott Long 			if(error)
2682aedd662SScott Long 				return error;
2692aedd662SScott Long 	}
2702aedd662SScott Long 	bus_generic_detach(sc->dev);
2712aedd662SScott Long 	return 0;
2722aedd662SScott Long }
2732aedd662SScott Long 
2742aedd662SScott Long /* ips_timeout is periodically called to make sure no commands sent
2752aedd662SScott Long  * to the card have become stuck.  If it finds a stuck command, it
2762aedd662SScott Long  * sets a flag so the driver won't start any more commands and then
2772aedd662SScott Long  * is periodically called to see if all outstanding commands have
2782aedd662SScott Long  * either finished or timed out.  Once timed out, an attempt to
2792aedd662SScott Long  * reinitialize the card is made.  If that fails, the driver gives
2802aedd662SScott Long  * up and declares the card dead. */
2812aedd662SScott Long static void ips_timeout(void *arg)
2822aedd662SScott Long {
2832aedd662SScott Long 	intrmask_t mask;
2842aedd662SScott Long 	ips_softc_t *sc = arg;
2852aedd662SScott Long 	int i, state = 0;
2862aedd662SScott Long 	ips_command_t *command;
2872aedd662SScott Long 	command = &sc->commandarray[0];
2882aedd662SScott Long 	mask = splbio();
2892aedd662SScott Long 	for(i = 0; i < sc->max_cmds; i++){
2902aedd662SScott Long 		if(!command[i].timeout){
2912aedd662SScott Long 			continue;
2922aedd662SScott Long 		}
2932aedd662SScott Long 		command[i].timeout--;
2942aedd662SScott Long 		if(!command[i].timeout){
2952aedd662SScott Long 			if(!(sc->state & IPS_TIMEOUT)){
2962aedd662SScott Long 				sc->state |= IPS_TIMEOUT;
2972aedd662SScott Long 				device_printf(sc->dev, "WARNING: command timeout. Adapter is in toaster mode, resetting to known state\n");
2982aedd662SScott Long 			}
2992aedd662SScott Long 			command[i].status.value = IPS_ERROR_STATUS;
3002aedd662SScott Long 			command[i].callback(&command[i]);
3012aedd662SScott Long 			/* hmm, this should be enough cleanup */
3022aedd662SScott Long 		} else
3032aedd662SScott Long 			state = 1;
3042aedd662SScott Long 	}
3052aedd662SScott Long 	if(!state && (sc->state & IPS_TIMEOUT)){
3062aedd662SScott Long 		if(sc->ips_adapter_reinit(sc, 1)){
3072aedd662SScott Long 			device_printf(sc->dev, "AIEE! adapter reset failed, giving up and going home! Have a nice day.\n");
3082aedd662SScott Long 			sc->state |= IPS_OFFLINE;
3092aedd662SScott Long 			sc->state &= ~IPS_TIMEOUT;
3102aedd662SScott Long 			/* Grr, I hate this solution. I run waiting commands
3112aedd662SScott Long 			   one at a time and error them out just before they
3122aedd662SScott Long 			   would go to the card. This sucks. */
3132aedd662SScott Long 		} else
3142aedd662SScott Long 			sc->state &= ~IPS_TIMEOUT;
3152aedd662SScott Long 		ips_run_waiting_command(sc);
3162aedd662SScott Long 	}
3172aedd662SScott Long 	if (sc->state != IPS_OFFLINE)
3182aedd662SScott Long 		sc->timer = timeout(ips_timeout, sc, 10*hz);
3192aedd662SScott Long 	splx(mask);
3202aedd662SScott Long }
3212aedd662SScott Long 
3222aedd662SScott Long /* check card and initialize it */
3232aedd662SScott Long int ips_adapter_init(ips_softc_t *sc)
3242aedd662SScott Long {
325dea4622dSScott Long         int i;
3262aedd662SScott Long         DEVICE_PRINTF(1,sc->dev, "initializing\n");
3272aedd662SScott Long         if (bus_dma_tag_create(	/* parent    */	sc->adapter_dmatag,
3282aedd662SScott Long 				/* alignemnt */	1,
3292aedd662SScott Long 				/* boundary  */	0,
3302aedd662SScott Long 				/* lowaddr   */	BUS_SPACE_MAXADDR_32BIT,
3312aedd662SScott Long 				/* highaddr  */	BUS_SPACE_MAXADDR,
3322aedd662SScott Long 				/* filter    */	NULL,
3332aedd662SScott Long 				/* filterarg */	NULL,
3342aedd662SScott Long 				/* maxsize   */	IPS_COMMAND_LEN +
3352aedd662SScott Long 						    IPS_MAX_SG_LEN,
3362aedd662SScott Long 				/* numsegs   */	1,
3372aedd662SScott Long 				/* maxsegsize*/	IPS_COMMAND_LEN +
3382aedd662SScott Long 						    IPS_MAX_SG_LEN,
3392aedd662SScott Long 				/* flags     */	0,
3402aedd662SScott Long 				&sc->command_dmatag) != 0) {
3412aedd662SScott Long                 device_printf(sc->dev, "can't alloc command dma tag\n");
3422aedd662SScott Long 		goto error;
3432aedd662SScott Long         }
3442aedd662SScott Long 	if (bus_dma_tag_create(	/* parent    */	sc->adapter_dmatag,
3452aedd662SScott Long 				/* alignemnt */	1,
3462aedd662SScott Long 				/* boundary  */	0,
3472aedd662SScott Long 				/* lowaddr   */	BUS_SPACE_MAXADDR_32BIT,
3482aedd662SScott Long 				/* highaddr  */	BUS_SPACE_MAXADDR,
3492aedd662SScott Long 				/* filter    */	NULL,
3502aedd662SScott Long 				/* filterarg */	NULL,
3512aedd662SScott Long 				/* maxsize   */	IPS_MAX_IOBUF_SIZE,
3522aedd662SScott Long 				/* numsegs   */	IPS_MAX_SG_ELEMENTS,
3532aedd662SScott Long 				/* maxsegsize*/	IPS_MAX_IOBUF_SIZE,
3542aedd662SScott Long 				/* flags     */	0,
3552aedd662SScott Long 				&sc->sg_dmatag) != 0) {
3562aedd662SScott Long 		device_printf(sc->dev, "can't alloc SG dma tag\n");
3572aedd662SScott Long 		goto error;
3582aedd662SScott Long 	}
3592aedd662SScott Long 	/* create one command buffer until we know how many commands this card
3602aedd662SScott Long            can handle */
3612aedd662SScott Long 	sc->max_cmds = 1;
3622aedd662SScott Long 	ips_cmdqueue_init(sc);
363dea4622dSScott Long 	callout_handle_init(&sc->timer);
3642aedd662SScott Long 
3652aedd662SScott Long 	if(sc->ips_adapter_reinit(sc, 0))
3662aedd662SScott Long 		goto error;
3672aedd662SScott Long 
3682aedd662SScott Long 	mtx_init(&sc->cmd_mtx, "ips command mutex", NULL, MTX_DEF);
369dea4622dSScott Long 	if ((i = ips_get_adapter_info(sc)) != 0) {
370dea4622dSScott Long 		device_printf(sc->dev, "failed to get adapter configuration data from device (%d)\n", i);
371dea4622dSScott Long 		goto error;
372dea4622dSScott Long 	}
373dea4622dSScott Long  	if ((i = ips_get_drive_info(sc)) != 0) {
374dea4622dSScott Long 		device_printf(sc->dev, "failed to get drive configuration data from device (%d)\n", i);
3752aedd662SScott Long 		goto error;
3762aedd662SScott Long 	}
3772aedd662SScott Long 	ips_update_nvram(sc); /* no error check as failure doesn't matter */
3782aedd662SScott Long 
3792aedd662SScott Long         ips_cmdqueue_free(sc);
3802aedd662SScott Long 	if(sc->adapter_info.max_concurrent_cmds)
3812aedd662SScott Long         	sc->max_cmds = min(128, sc->adapter_info.max_concurrent_cmds);
3822aedd662SScott Long 	else
3832aedd662SScott Long 		sc->max_cmds = 32;
3842aedd662SScott Long         if(ips_cmdqueue_init(sc)){
3852aedd662SScott Long 		device_printf(sc->dev, "failed to initialize command buffers\n");
3862aedd662SScott Long 		goto error;
3872aedd662SScott Long 	}
3882aedd662SScott Long         sc->device_file = make_dev(&ips_cdevsw, device_get_unit(sc->dev), UID_ROOT, GID_OPERATOR,
3892aedd662SScott Long                                         S_IRUSR | S_IWUSR, "ips%d", device_get_unit(sc->dev));
3902aedd662SScott Long 	sc->device_file->si_drv1 = sc;
3912aedd662SScott Long 	ips_diskdev_init(sc);
3922aedd662SScott Long 	sc->timer = timeout(ips_timeout, sc, 10*hz);
3932aedd662SScott Long         return 0;
3942aedd662SScott Long 
3952aedd662SScott Long error:
3962aedd662SScott Long 	ips_adapter_free(sc);
3972aedd662SScott Long 	return ENXIO;
3982aedd662SScott Long }
3992aedd662SScott Long 
4002aedd662SScott Long /* see if we should reinitialize the card and wait for it to timeout or complete initialization */
4012aedd662SScott Long int ips_morpheus_reinit(ips_softc_t *sc, int force)
4022aedd662SScott Long {
4032aedd662SScott Long         u_int32_t tmp;
4042aedd662SScott Long 	int i;
4052aedd662SScott Long 
4062aedd662SScott Long 	tmp = ips_read_4(sc, MORPHEUS_REG_OISR);
4072aedd662SScott Long 	if(!force && (ips_read_4(sc, MORPHEUS_REG_OMR0) >= IPS_POST1_OK) &&
4082aedd662SScott Long 	    (ips_read_4(sc, MORPHEUS_REG_OMR1) != 0xdeadbeef) && !tmp){
4092aedd662SScott Long 		ips_write_4(sc, MORPHEUS_REG_OIMR, 0);
4102aedd662SScott Long 		return 0;
4112aedd662SScott Long 	}
4122aedd662SScott Long 	ips_write_4(sc, MORPHEUS_REG_OIMR, 0xff);
4132aedd662SScott Long 	ips_read_4(sc, MORPHEUS_REG_OIMR);
4142aedd662SScott Long 
4152aedd662SScott Long 	device_printf(sc->dev, "resetting adapter, this may take up to 5 minutes\n");
4162aedd662SScott Long 	ips_write_4(sc, MORPHEUS_REG_IDR, 0x80000000);
4172aedd662SScott Long 	DELAY(5000000);
4182aedd662SScott Long 	pci_read_config(sc->dev, 0, 4);
4192aedd662SScott Long 
4202aedd662SScott Long 	tmp = ips_read_4(sc, MORPHEUS_REG_OISR);
4212aedd662SScott Long 	for(i = 0; i < 45 && !(tmp & MORPHEUS_BIT_POST1); i++){
4222aedd662SScott Long 		DELAY(1000000);
4232aedd662SScott Long 		DEVICE_PRINTF(2, sc->dev, "post1: %d\n", i);
4242aedd662SScott Long 		tmp = ips_read_4(sc, MORPHEUS_REG_OISR);
4252aedd662SScott Long 	}
4262aedd662SScott Long 	if(tmp & MORPHEUS_BIT_POST1)
4272aedd662SScott Long 		ips_write_4(sc, MORPHEUS_REG_OISR, MORPHEUS_BIT_POST1);
4282aedd662SScott Long 
4292aedd662SScott Long         if( i == 45 || ips_read_4(sc, MORPHEUS_REG_OMR0) < IPS_POST1_OK){
4302aedd662SScott Long                 device_printf(sc->dev,"Adapter error during initialization.\n");
4312aedd662SScott Long 		return 1;
4322aedd662SScott Long         }
4332aedd662SScott Long 	for(i = 0; i < 240 && !(tmp & MORPHEUS_BIT_POST2); i++){
4342aedd662SScott Long 		DELAY(1000000);
4352aedd662SScott Long 		DEVICE_PRINTF(2, sc->dev, "post2: %d\n", i);
4362aedd662SScott Long 		tmp = ips_read_4(sc, MORPHEUS_REG_OISR);
4372aedd662SScott Long 	}
4382aedd662SScott Long 	if(tmp & MORPHEUS_BIT_POST2)
4392aedd662SScott Long 		ips_write_4(sc, MORPHEUS_REG_OISR, MORPHEUS_BIT_POST2);
4402aedd662SScott Long 
4412aedd662SScott Long 	if(i == 240 || !ips_read_4(sc, MORPHEUS_REG_OMR1)){
4422aedd662SScott Long 		device_printf(sc->dev, "adapter failed config check\n");
4432aedd662SScott Long 		return 1;
4442aedd662SScott Long         }
4452aedd662SScott Long 	ips_write_4(sc, MORPHEUS_REG_OIMR, 0);
4462aedd662SScott Long 	if(force && ips_clear_adapter(sc)){
4472aedd662SScott Long 		device_printf(sc->dev, "adapter clear failed\n");
4482aedd662SScott Long 		return 1;
4492aedd662SScott Long 	}
4502aedd662SScott Long 	return 0;
4512aedd662SScott Long }
4522aedd662SScott Long 
4532aedd662SScott Long /* clean up so we can unload the driver. */
4542aedd662SScott Long int ips_adapter_free(ips_softc_t *sc)
4552aedd662SScott Long {
4562aedd662SScott Long 	int error = 0;
4572aedd662SScott Long 	intrmask_t mask;
4582aedd662SScott Long 	if(sc->state & IPS_DEV_OPEN)
4592aedd662SScott Long 		return EBUSY;
4602aedd662SScott Long 	if((error = ips_diskdev_free(sc)))
4612aedd662SScott Long 		return error;
4622aedd662SScott Long 	if(ips_cmdqueue_free(sc)){
4632aedd662SScott Long 		device_printf(sc->dev,
4642aedd662SScott Long 		     "trying to exit when command queue is not empty!\n");
4652aedd662SScott Long 		return EBUSY;
4662aedd662SScott Long 	}
4672aedd662SScott Long 	DEVICE_PRINTF(1, sc->dev, "free\n");
4682aedd662SScott Long 	mask = splbio();
4692aedd662SScott Long 	untimeout(ips_timeout, sc, sc->timer);
4702aedd662SScott Long 	splx(mask);
4712aedd662SScott Long 	if (mtx_initialized(&sc->cmd_mtx))
4722aedd662SScott Long 		mtx_destroy(&sc->cmd_mtx);
4732aedd662SScott Long 
4742aedd662SScott Long 	if(sc->sg_dmatag)
4752aedd662SScott Long 		bus_dma_tag_destroy(sc->sg_dmatag);
4762aedd662SScott Long 	if(sc->command_dmatag)
4772aedd662SScott Long 		bus_dma_tag_destroy(sc->command_dmatag);
4782aedd662SScott Long 	if(sc->device_file)
4792aedd662SScott Long 	        destroy_dev(sc->device_file);
4802aedd662SScott Long         return 0;
4812aedd662SScott Long }
4822aedd662SScott Long 
4832aedd662SScott Long void ips_morpheus_intr(void *void_sc)
4842aedd662SScott Long {
4852aedd662SScott Long         ips_softc_t *sc = (ips_softc_t *)void_sc;
4862aedd662SScott Long 	u_int32_t oisr, iisr;
4872aedd662SScott Long 	int cmdnumber;
4882aedd662SScott Long 	ips_cmd_status_t status;
4892aedd662SScott Long 
4902aedd662SScott Long 	iisr =ips_read_4(sc, MORPHEUS_REG_IISR);
4912aedd662SScott Long 	oisr =ips_read_4(sc, MORPHEUS_REG_OISR);
4922aedd662SScott Long         PRINTF(9,"interrupt registers in:%x out:%x\n",iisr, oisr);
4932aedd662SScott Long 	if(!(oisr & MORPHEUS_BIT_CMD_IRQ)){
4942aedd662SScott Long 		DEVICE_PRINTF(2,sc->dev, "got a non-command irq\n");
4952aedd662SScott Long 		return;
4962aedd662SScott Long 	}
4972aedd662SScott Long 	while((status.value = ips_read_4(sc, MORPHEUS_REG_OQPR)) != 0xffffffff){
4982aedd662SScott Long 		cmdnumber = status.fields.command_id;
4992aedd662SScott Long 		sc->commandarray[cmdnumber].status.value = status.value;
5002aedd662SScott Long 		sc->commandarray[cmdnumber].timeout = 0;
5012aedd662SScott Long 		sc->commandarray[cmdnumber].callback(&(sc->commandarray[cmdnumber]));
5022aedd662SScott Long 
5032aedd662SScott Long 
5042aedd662SScott Long 		DEVICE_PRINTF(9,sc->dev, "got command %d\n", cmdnumber);
5052aedd662SScott Long 	}
5062aedd662SScott Long         return;
5072aedd662SScott Long }
5082aedd662SScott Long 
5092aedd662SScott Long void ips_issue_morpheus_cmd(ips_command_t *command)
5102aedd662SScott Long {
5112aedd662SScott Long 	intrmask_t mask = splbio();
5122aedd662SScott Long 	/* hmmm, is there a cleaner way to do this? */
5132aedd662SScott Long 	if(command->sc->state & IPS_OFFLINE){
5142aedd662SScott Long 		splx(mask);
5152aedd662SScott Long 		command->status.value = IPS_ERROR_STATUS;
5162aedd662SScott Long 		command->callback(command);
5172aedd662SScott Long 		return;
5182aedd662SScott Long 	}
5192aedd662SScott Long 	command->timeout = 10;
5202aedd662SScott Long 	ips_write_4(command->sc, MORPHEUS_REG_IQPR, command->command_phys_addr);
5212aedd662SScott Long 	splx(mask);
5222aedd662SScott Long }
5232aedd662SScott Long 
5242aedd662SScott Long static void ips_copperhead_queue_callback(void *queueptr, bus_dma_segment_t *segments,int segnum, int error)
5252aedd662SScott Long {
5262aedd662SScott Long 	ips_copper_queue_t *queue = queueptr;
5272aedd662SScott Long 	if(error){
5282aedd662SScott Long 		return;
5292aedd662SScott Long 	}
5302aedd662SScott Long 	queue->base_phys_addr = segments[0].ds_addr;
5312aedd662SScott Long }
5322aedd662SScott Long 
5332aedd662SScott Long static int ips_copperhead_queue_init(ips_softc_t *sc)
5342aedd662SScott Long {
5352aedd662SScott Long 	int error;
5362aedd662SScott Long 	bus_dma_tag_t dmatag;
5372aedd662SScott Long 	bus_dmamap_t dmamap;
5382aedd662SScott Long        	if (bus_dma_tag_create(	/* parent    */	sc->adapter_dmatag,
5392aedd662SScott Long 				/* alignemnt */	1,
5402aedd662SScott Long 				/* boundary  */	0,
5412aedd662SScott Long 				/* lowaddr   */	BUS_SPACE_MAXADDR_32BIT,
5422aedd662SScott Long 				/* highaddr  */	BUS_SPACE_MAXADDR,
5432aedd662SScott Long 				/* filter    */	NULL,
5442aedd662SScott Long 				/* filterarg */	NULL,
5452aedd662SScott Long 				/* maxsize   */	sizeof(ips_copper_queue_t),
5462aedd662SScott Long 				/* numsegs   */	1,
5472aedd662SScott Long 				/* maxsegsize*/	sizeof(ips_copper_queue_t),
5482aedd662SScott Long 				/* flags     */	0,
5492aedd662SScott Long 				&dmatag) != 0) {
5502aedd662SScott Long                 device_printf(sc->dev, "can't alloc dma tag for statue queue\n");
5512aedd662SScott Long 		error = ENOMEM;
5522aedd662SScott Long 		goto exit;
5532aedd662SScott Long         }
5542aedd662SScott Long 	if(bus_dmamem_alloc(dmatag, (void *)&(sc->copper_queue),
5552aedd662SScott Long 	   		    BUS_DMA_NOWAIT, &dmamap)){
5562aedd662SScott Long 		error = ENOMEM;
5572aedd662SScott Long 		goto exit;
5582aedd662SScott Long 	}
5592aedd662SScott Long 	bzero(sc->copper_queue, sizeof(ips_copper_queue_t));
5602aedd662SScott Long 	sc->copper_queue->dmatag = dmatag;
5612aedd662SScott Long 	sc->copper_queue->dmamap = dmamap;
5622aedd662SScott Long 	sc->copper_queue->nextstatus = 1;
5632aedd662SScott Long 	bus_dmamap_load(dmatag, dmamap,
5642aedd662SScott Long 			&(sc->copper_queue->status[0]), IPS_MAX_CMD_NUM * 4,
5652aedd662SScott Long 			ips_copperhead_queue_callback, sc->copper_queue,
5662aedd662SScott Long 			BUS_DMA_NOWAIT);
5672aedd662SScott Long 	if(sc->copper_queue->base_phys_addr == 0){
5682aedd662SScott Long 		error = ENOMEM;
5692aedd662SScott Long 		goto exit;
5702aedd662SScott Long 	}
5712aedd662SScott Long 	ips_write_4(sc, COPPER_REG_SQSR, sc->copper_queue->base_phys_addr);
5722aedd662SScott Long 	ips_write_4(sc, COPPER_REG_SQER, sc->copper_queue->base_phys_addr +
5732aedd662SScott Long 		    IPS_MAX_CMD_NUM * 4);
5742aedd662SScott Long 	ips_write_4(sc, COPPER_REG_SQHR, sc->copper_queue->base_phys_addr + 4);
5752aedd662SScott Long 	ips_write_4(sc, COPPER_REG_SQTR, sc->copper_queue->base_phys_addr);
5762aedd662SScott Long 
5772aedd662SScott Long 
5782aedd662SScott Long 	return 0;
5792aedd662SScott Long exit:
5802aedd662SScott Long 	bus_dmamem_free(dmatag, sc->copper_queue, dmamap);
5812aedd662SScott Long 	bus_dma_tag_destroy(dmatag);
5822aedd662SScott Long 	return error;
5832aedd662SScott Long }
5842aedd662SScott Long 
5852aedd662SScott Long /* see if we should reinitialize the card and wait for it to timeout or complete initialization FIXME */
5862aedd662SScott Long int ips_copperhead_reinit(ips_softc_t *sc, int force)
5872aedd662SScott Long {
5882aedd662SScott Long 	int i, j;
5892aedd662SScott Long 	u_int32_t postcode = 0, configstatus = 0;
5902aedd662SScott Long 	ips_write_1(sc, COPPER_REG_SCPR, 0x80);
5912aedd662SScott Long 	ips_write_1(sc, COPPER_REG_SCPR, 0);
5922aedd662SScott Long 	device_printf(sc->dev, "reinitializing adapter, this could take several minutes.\n");
5932aedd662SScott Long 	for(j = 0; j < 2; j++){
5942aedd662SScott Long 		postcode <<= 8;
5952aedd662SScott Long 		for(i = 0; i < 45; i++){
5962aedd662SScott Long 			if(ips_read_1(sc, COPPER_REG_HISR) & COPPER_GHI_BIT){
5972aedd662SScott Long 				postcode |= ips_read_1(sc, COPPER_REG_ISPR);
5982aedd662SScott Long 				ips_write_1(sc, COPPER_REG_HISR,
5992aedd662SScott Long 					    COPPER_GHI_BIT);
6002aedd662SScott Long 				break;
6012aedd662SScott Long 			} else
6022aedd662SScott Long 				DELAY(1000000);
6032aedd662SScott Long 		}
6042aedd662SScott Long 		if(i == 45)
6052aedd662SScott Long 			return 1;
6062aedd662SScott Long 	}
6072aedd662SScott Long 	for(j = 0; j < 2; j++){
6082aedd662SScott Long 		configstatus <<= 8;
6092aedd662SScott Long 		for(i = 0; i < 240; i++){
6102aedd662SScott Long 			if(ips_read_1(sc, COPPER_REG_HISR) & COPPER_GHI_BIT){
6112aedd662SScott Long 				configstatus |= ips_read_1(sc, COPPER_REG_ISPR);
6122aedd662SScott Long 				ips_write_1(sc, COPPER_REG_HISR,
6132aedd662SScott Long 					    COPPER_GHI_BIT);
6142aedd662SScott Long 				break;
6152aedd662SScott Long 			} else
6162aedd662SScott Long 				DELAY(1000000);
6172aedd662SScott Long 		}
6182aedd662SScott Long 		if(i == 240)
6192aedd662SScott Long 			return 1;
6202aedd662SScott Long 	}
6212aedd662SScott Long 	for(i = 0; i < 240; i++){
6222aedd662SScott Long 		if(!(ips_read_1(sc, COPPER_REG_CBSP) & COPPER_OP_BIT)){
6232aedd662SScott Long 			break;
6242aedd662SScott Long 		} else
6252aedd662SScott Long 			DELAY(1000000);
6262aedd662SScott Long 	}
6272aedd662SScott Long 	if(i == 240)
6282aedd662SScott Long 		return 1;
6292aedd662SScott Long 	ips_write_2(sc, COPPER_REG_CCCR, 0x1000 | COPPER_ILE_BIT);
6302aedd662SScott Long 	ips_write_1(sc, COPPER_REG_SCPR, COPPER_EBM_BIT);
6312aedd662SScott Long 	ips_copperhead_queue_init(sc);
6322aedd662SScott Long 	ips_write_1(sc, COPPER_REG_HISR, COPPER_GHI_BIT);
6332aedd662SScott Long 	i = ips_read_1(sc, COPPER_REG_SCPR);
6342aedd662SScott Long 	ips_write_1(sc, COPPER_REG_HISR, COPPER_EI_BIT);
6352aedd662SScott Long 	if(!configstatus){
6362aedd662SScott Long 		device_printf(sc->dev, "adapter initialization failed\n");
6372aedd662SScott Long 		return 1;
6382aedd662SScott Long 	}
6392aedd662SScott Long 	if(force && ips_clear_adapter(sc)){
6402aedd662SScott Long 		device_printf(sc->dev, "adapter clear failed\n");
6412aedd662SScott Long 		return 1;
6422aedd662SScott Long 	}
6432aedd662SScott Long 	return 0;
6442aedd662SScott Long }
6452aedd662SScott Long static u_int32_t ips_copperhead_cmd_status(ips_softc_t *sc)
6462aedd662SScott Long {
6472aedd662SScott Long 	intrmask_t mask;
6482aedd662SScott Long 	u_int32_t value;
6492aedd662SScott Long 	int statnum = sc->copper_queue->nextstatus++;
6502aedd662SScott Long 	if(sc->copper_queue->nextstatus == IPS_MAX_CMD_NUM)
6512aedd662SScott Long 		sc->copper_queue->nextstatus = 0;
6522aedd662SScott Long 	mask = splbio();
6532aedd662SScott Long 	value = sc->copper_queue->status[statnum];
6542aedd662SScott Long 	ips_write_4(sc, COPPER_REG_SQTR, sc->copper_queue->base_phys_addr +
6552aedd662SScott Long 		    4 * statnum);
6562aedd662SScott Long 	splx(mask);
6572aedd662SScott Long 	return value;
6582aedd662SScott Long }
6592aedd662SScott Long 
6602aedd662SScott Long 
6612aedd662SScott Long void ips_copperhead_intr(void *void_sc)
6622aedd662SScott Long {
6632aedd662SScott Long         ips_softc_t *sc = (ips_softc_t *)void_sc;
6642aedd662SScott Long 	int cmdnumber;
6652aedd662SScott Long 	ips_cmd_status_t status;
6662aedd662SScott Long 
6672aedd662SScott Long 	while(ips_read_1(sc, COPPER_REG_HISR) & COPPER_SCE_BIT){
6682aedd662SScott Long 		status.value = ips_copperhead_cmd_status(sc);
6692aedd662SScott Long 		cmdnumber = status.fields.command_id;
6702aedd662SScott Long 		sc->commandarray[cmdnumber].status.value = status.value;
6712aedd662SScott Long 		sc->commandarray[cmdnumber].timeout = 0;
6722aedd662SScott Long 		sc->commandarray[cmdnumber].callback(&(sc->commandarray[cmdnumber]));
6732aedd662SScott Long 		PRINTF(9, "ips: got command %d\n", cmdnumber);
6742aedd662SScott Long 	}
6752aedd662SScott Long         return;
6762aedd662SScott Long }
6772aedd662SScott Long 
6782aedd662SScott Long void ips_issue_copperhead_cmd(ips_command_t *command)
6792aedd662SScott Long {
6802aedd662SScott Long 	int i;
6812aedd662SScott Long 	intrmask_t mask = splbio();
6822aedd662SScott Long 	/* hmmm, is there a cleaner way to do this? */
6832aedd662SScott Long 	if(command->sc->state & IPS_OFFLINE){
6842aedd662SScott Long 		splx(mask);
6852aedd662SScott Long 		command->status.value = IPS_ERROR_STATUS;
6862aedd662SScott Long 		command->callback(command);
6872aedd662SScott Long 		return;
6882aedd662SScott Long 	}
6892aedd662SScott Long 	command->timeout = 10;
6902aedd662SScott Long 	for(i = 0; ips_read_4(command->sc, COPPER_REG_CCCR) & COPPER_SEM_BIT;
6912aedd662SScott Long 	    i++ ){
6922aedd662SScott Long 		if( i == 20){
6932aedd662SScott Long printf("sem bit still set, can't send a command\n");
6942aedd662SScott Long 			splx(mask);
6952aedd662SScott Long 			return;
6962aedd662SScott Long 		}
6972aedd662SScott Long 		DELAY(500);/* need to do a delay here */
6982aedd662SScott Long 	}
6992aedd662SScott Long 	ips_write_4(command->sc, COPPER_REG_CCSAR, command->command_phys_addr);
7002aedd662SScott Long 	ips_write_2(command->sc, COPPER_REG_CCCR, COPPER_CMD_START);
7012aedd662SScott Long 	splx(mask);
7022aedd662SScott Long }
7032aedd662SScott Long 
704