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