File:  [DragonFly] / src / sys / dev / raid / mlx / mlx.c
Revision 1.7: download - view: text, annotated - select for diffs
Thu May 13 23:49:19 2004 UTC (9 years, 11 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).

d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device.  It was never
used for that purpose.

d_clone will be more fully implemented as work continues.  We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads.  This is something we will be needing later
on.

    1: /*-
    2:  * Copyright (c) 1999 Michael Smith
    3:  * All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  *
   14:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24:  * SUCH DAMAGE.
   25:  *
   26:  *	$FreeBSD: src/sys/dev/mlx/mlx.c,v 1.14.2.5 2001/09/11 09:49:53 kris Exp $
   27:  *	$DragonFly: src/sys/dev/raid/mlx/mlx.c,v 1.7 2004/05/13 23:49:19 dillon Exp $
   28:  */
   29: 
   30: /*
   31:  * Driver for the Mylex DAC960 family of RAID controllers.
   32:  */
   33: 
   34: #include <sys/param.h>
   35: #include <sys/systm.h>
   36: #include <sys/malloc.h>
   37: #include <sys/kernel.h>
   38: 
   39: #include <sys/bus.h>
   40: #include <sys/conf.h>
   41: #include <sys/devicestat.h>
   42: #include <sys/disk.h>
   43: #include <sys/stat.h>
   44: 
   45: #include <machine/resource.h>
   46: #include <machine/bus_memio.h>
   47: #include <machine/bus_pio.h>
   48: #include <machine/bus.h>
   49: #include <machine/clock.h>
   50: #include <sys/rman.h>
   51: 
   52: #include "mlx_compat.h"
   53: #include "mlxio.h"
   54: #include "mlxvar.h"
   55: #include "mlxreg.h"
   56: 
   57: #define MLX_CDEV_MAJOR	130
   58: 
   59: static struct cdevsw mlx_cdevsw = {
   60: 		/* name */ 	"mlx",
   61: 		/* maj */	MLX_CDEV_MAJOR,
   62: 		/* flags */	0,
   63: 		/* port */	NULL,
   64: 		/* clone */	NULL,
   65: 
   66: 		/* open */	mlx_open,
   67: 		/* close */	mlx_close,
   68: 		/* read */	noread,
   69: 		/* write */	nowrite,
   70: 		/* ioctl */	mlx_ioctl,
   71: 		/* poll */	nopoll,
   72: 		/* mmap */	nommap,
   73: 		/* strategy */	nostrategy,
   74: 		/* dump */	nodump,
   75: 		/* psize */ 	nopsize
   76: };
   77: 
   78: devclass_t	mlx_devclass;
   79: 
   80: /*
   81:  * Per-interface accessor methods
   82:  */
   83: static int			mlx_v3_tryqueue(struct mlx_softc *sc, struct mlx_command *mc);
   84: static int			mlx_v3_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status);
   85: static void			mlx_v3_intaction(struct mlx_softc *sc, int action);
   86: static int			mlx_v3_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2);
   87: 
   88: static int			mlx_v4_tryqueue(struct mlx_softc *sc, struct mlx_command *mc);
   89: static int			mlx_v4_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status);
   90: static void			mlx_v4_intaction(struct mlx_softc *sc, int action);
   91: static int			mlx_v4_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2);
   92: 
   93: static int			mlx_v5_tryqueue(struct mlx_softc *sc, struct mlx_command *mc);
   94: static int			mlx_v5_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status);
   95: static void			mlx_v5_intaction(struct mlx_softc *sc, int action);
   96: static int			mlx_v5_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2);
   97: 
   98: /*
   99:  * Status monitoring
  100:  */
  101: static void			mlx_periodic(void *data);
  102: static void			mlx_periodic_enquiry(struct mlx_command *mc);
  103: static void			mlx_periodic_eventlog_poll(struct mlx_softc *sc);
  104: static void			mlx_periodic_eventlog_respond(struct mlx_command *mc);
  105: static void			mlx_periodic_rebuild(struct mlx_command *mc);
  106: 
  107: /*
  108:  * Channel Pause
  109:  */
  110: static void			mlx_pause_action(struct mlx_softc *sc);
  111: static void			mlx_pause_done(struct mlx_command *mc);
  112: 
  113: /*
  114:  * Command submission.
  115:  */
  116: static void			*mlx_enquire(struct mlx_softc *sc, int command, size_t bufsize, 
  117: 					     void (*complete)(struct mlx_command *mc));
  118: static int			mlx_flush(struct mlx_softc *sc);
  119: static int			mlx_check(struct mlx_softc *sc, int drive);
  120: static int			mlx_rebuild(struct mlx_softc *sc, int channel, int target);
  121: static int			mlx_wait_command(struct mlx_command *mc);
  122: static int			mlx_poll_command(struct mlx_command *mc);
  123: static void			mlx_startio(struct mlx_softc *sc);
  124: static void			mlx_completeio(struct mlx_command *mc);
  125: static int			mlx_user_command(struct mlx_softc *sc, struct mlx_usercommand *mu);
  126: 
  127: /*
  128:  * Command buffer allocation.
  129:  */
  130: static struct mlx_command	*mlx_alloccmd(struct mlx_softc *sc);
  131: static void			mlx_releasecmd(struct mlx_command *mc);
  132: static void			mlx_freecmd(struct mlx_command *mc);
  133: 
  134: /*
  135:  * Command management.
  136:  */
  137: static int			mlx_getslot(struct mlx_command *mc);
  138: static void			mlx_mapcmd(struct mlx_command *mc);
  139: static void			mlx_unmapcmd(struct mlx_command *mc);
  140: static int			mlx_start(struct mlx_command *mc);
  141: static int			mlx_done(struct mlx_softc *sc);
  142: static void			mlx_complete(struct mlx_softc *sc);
  143: 
  144: /*
  145:  * Debugging.
  146:  */
  147: static char			*mlx_diagnose_command(struct mlx_command *mc);
  148: static void			mlx_describe_controller(struct mlx_softc *sc);
  149: static int			mlx_fw_message(struct mlx_softc *sc, int status, int param1, int param2);
  150: 
  151: /*
  152:  * Utility functions.
  153:  */
  154: static struct mlx_sysdrive	*mlx_findunit(struct mlx_softc *sc, int unit);
  155: 
  156: /********************************************************************************
  157:  ********************************************************************************
  158:                                                                 Public Interfaces
  159:  ********************************************************************************
  160:  ********************************************************************************/
  161: 
  162: /********************************************************************************
  163:  * Free all of the resources associated with (sc)
  164:  *
  165:  * Should not be called if the controller is active.
  166:  */
  167: void
  168: mlx_free(struct mlx_softc *sc)
  169: {
  170:     struct mlx_command	*mc;
  171: 
  172:     debug_called(1);
  173: 
  174:     /* cancel status timeout */
  175:     untimeout(mlx_periodic, sc, sc->mlx_timeout);
  176: 
  177:     /* throw away any command buffers */
  178:     while ((mc = TAILQ_FIRST(&sc->mlx_freecmds)) != NULL) {
  179: 	TAILQ_REMOVE(&sc->mlx_freecmds, mc, mc_link);
  180: 	mlx_freecmd(mc);
  181:     }
  182: 
  183:     /* destroy data-transfer DMA tag */
  184:     if (sc->mlx_buffer_dmat)
  185: 	bus_dma_tag_destroy(sc->mlx_buffer_dmat);
  186: 
  187:     /* free and destroy DMA memory and tag for s/g lists */
  188:     if (sc->mlx_sgtable)
  189: 	bus_dmamem_free(sc->mlx_sg_dmat, sc->mlx_sgtable, sc->mlx_sg_dmamap);
  190:     if (sc->mlx_sg_dmat)
  191: 	bus_dma_tag_destroy(sc->mlx_sg_dmat);
  192: 
  193:     /* disconnect the interrupt handler */
  194:     if (sc->mlx_intr)
  195: 	bus_teardown_intr(sc->mlx_dev, sc->mlx_irq, sc->mlx_intr);
  196:     if (sc->mlx_irq != NULL)
  197: 	bus_release_resource(sc->mlx_dev, SYS_RES_IRQ, 0, sc->mlx_irq);
  198: 
  199:     /* destroy the parent DMA tag */
  200:     if (sc->mlx_parent_dmat)
  201: 	bus_dma_tag_destroy(sc->mlx_parent_dmat);
  202: 
  203:     /* release the register window mapping */
  204:     if (sc->mlx_mem != NULL)
  205: 	bus_release_resource(sc->mlx_dev, sc->mlx_mem_type, sc->mlx_mem_rid, sc->mlx_mem);
  206: 
  207:     /* free controller enquiry data */
  208:     if (sc->mlx_enq2 != NULL)
  209: 	free(sc->mlx_enq2, M_DEVBUF);
  210: 
  211:     /* destroy control device */
  212:     if (sc->mlx_dev_t != (dev_t)NULL)
  213: 	destroy_dev(sc->mlx_dev_t);
  214: }
  215: 
  216: /********************************************************************************
  217:  * Map the scatter/gather table into bus space
  218:  */
  219: static void
  220: mlx_dma_map_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
  221: {
  222:     struct mlx_softc	*sc = (struct mlx_softc *)arg;
  223: 
  224:     debug_called(1);
  225: 
  226:     /* save base of s/g table's address in bus space */
  227:     sc->mlx_sgbusaddr = segs->ds_addr;
  228: }
  229: 
  230: static int
  231: mlx_sglist_map(struct mlx_softc *sc)
  232: {
  233:     size_t	segsize;
  234:     int		error, ncmd;
  235: 
  236:     debug_called(1);
  237: 
  238:     /* destroy any existing mappings */
  239:     if (sc->mlx_sgtable)
  240: 	bus_dmamem_free(sc->mlx_sg_dmat, sc->mlx_sgtable, sc->mlx_sg_dmamap);
  241:     if (sc->mlx_sg_dmat)
  242: 	bus_dma_tag_destroy(sc->mlx_sg_dmat);
  243: 
  244:     /*
  245:      * Create a single tag describing a region large enough to hold all of
  246:      * the s/g lists we will need.  If we're called early on, we don't know how
  247:      * many commands we're going to be asked to support, so only allocate enough
  248:      * for a couple.
  249:      */
  250:     if (sc->mlx_enq2 == NULL) {
  251: 	ncmd = 2;
  252:     } else {
  253: 	ncmd = sc->mlx_enq2->me_max_commands;
  254:     }
  255:     segsize = sizeof(struct mlx_sgentry) * MLX_NSEG * ncmd;
  256:     error = bus_dma_tag_create(sc->mlx_parent_dmat, 	/* parent */
  257: 			       1, 0, 			/* alignment, boundary */
  258: 			       BUS_SPACE_MAXADDR,	/* lowaddr */
  259: 			       BUS_SPACE_MAXADDR, 	/* highaddr */
  260: 			       NULL, NULL, 		/* filter, filterarg */
  261: 			       segsize, 1,		/* maxsize, nsegments */
  262: 			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
  263: 			       0,			/* flags */
  264: 			       &sc->mlx_sg_dmat);
  265:     if (error != 0) {
  266: 	device_printf(sc->mlx_dev, "can't allocate scatter/gather DMA tag\n");
  267: 	return(ENOMEM);
  268:     }
  269: 
  270:     /*
  271:      * Allocate enough s/g maps for all commands and permanently map them into
  272:      * controller-visible space.
  273:      *	
  274:      * XXX this assumes we can get enough space for all the s/g maps in one 
  275:      * contiguous slab.  We may need to switch to a more complex arrangement where
  276:      * we allocate in smaller chunks and keep a lookup table from slot to bus address.
  277:      */
  278:     error = bus_dmamem_alloc(sc->mlx_sg_dmat, (void **)&sc->mlx_sgtable, BUS_DMA_NOWAIT, &sc->mlx_sg_dmamap);
  279:     if (error) {
  280: 	device_printf(sc->mlx_dev, "can't allocate s/g table\n");
  281: 	return(ENOMEM);
  282:     }
  283:     bus_dmamap_load(sc->mlx_sg_dmat, sc->mlx_sg_dmamap, sc->mlx_sgtable, segsize, mlx_dma_map_sg, sc, 0);
  284:     return(0);
  285: }
  286: 
  287: /********************************************************************************
  288:  * Initialise the controller and softc
  289:  */
  290: int
  291: mlx_attach(struct mlx_softc *sc)
  292: {
  293:     struct mlx_enquiry_old	*meo;
  294:     int				rid, error, fwminor, hscode, hserror, hsparam1, hsparam2, hsmsg;
  295: 
  296:     debug_called(1);
  297: 
  298:     /*
  299:      * Initialise per-controller queues.
  300:      */
  301:     TAILQ_INIT(&sc->mlx_work);
  302:     TAILQ_INIT(&sc->mlx_freecmds);
  303:     MLX_BIO_QINIT(sc->mlx_bioq);
  304: 
  305:     /* 
  306:      * Select accessor methods based on controller interface type.
  307:      */
  308:     switch(sc->mlx_iftype) {
  309:     case MLX_IFTYPE_2:
  310:     case MLX_IFTYPE_3:
  311: 	sc->mlx_tryqueue	= mlx_v3_tryqueue;
  312: 	sc->mlx_findcomplete	= mlx_v3_findcomplete;
  313: 	sc->mlx_intaction	= mlx_v3_intaction;
  314: 	sc->mlx_fw_handshake	= mlx_v3_fw_handshake;
  315: 	break;
  316:     case MLX_IFTYPE_4:
  317: 	sc->mlx_tryqueue	= mlx_v4_tryqueue;
  318: 	sc->mlx_findcomplete	= mlx_v4_findcomplete;
  319: 	sc->mlx_intaction	= mlx_v4_intaction;
  320: 	sc->mlx_fw_handshake	= mlx_v4_fw_handshake;
  321: 	break;
  322:     case MLX_IFTYPE_5:
  323: 	sc->mlx_tryqueue	= mlx_v5_tryqueue;
  324: 	sc->mlx_findcomplete	= mlx_v5_findcomplete;
  325: 	sc->mlx_intaction	= mlx_v5_intaction;
  326: 	sc->mlx_fw_handshake	= mlx_v5_fw_handshake;
  327: 	break;
  328:     default:
  329: 	mlx_free(sc);
  330: 	return(ENXIO);		/* should never happen */
  331:     }
  332: 
  333:     /* disable interrupts before we start talking to the controller */
  334:     sc->mlx_intaction(sc, MLX_INTACTION_DISABLE);
  335: 
  336:     /* 
  337:      * Wait for the controller to come ready, handshake with the firmware if required.
  338:      * This is typically only necessary on platforms where the controller BIOS does not
  339:      * run.
  340:      */
  341:     hsmsg = 0;
  342:     DELAY(1000);
  343:     while ((hscode = sc->mlx_fw_handshake(sc, &hserror, &hsparam1, &hsparam2)) != 0) {
  344: 	/* report first time around... */
  345: 	if (hsmsg == 0) {
  346: 	    device_printf(sc->mlx_dev, "controller initialisation in progress...\n");
  347: 	    hsmsg = 1;
  348: 	}
  349: 	/* did we get a real message? */
  350: 	if (hscode == 2) {
  351: 	    hscode = mlx_fw_message(sc, hserror, hsparam1, hsparam2);
  352: 	    /* fatal initialisation error? */
  353: 	    if (hscode != 0) {
  354: 		mlx_free(sc);
  355: 		return(ENXIO);
  356: 	    }
  357: 	}
  358:     }
  359:     if (hsmsg == 1)
  360: 	device_printf(sc->mlx_dev, "initialisation complete.\n");
  361: 
  362:     /* 
  363:      * Allocate and connect our interrupt.
  364:      */
  365:     rid = 0;
  366:     sc->mlx_irq = bus_alloc_resource(sc->mlx_dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
  367:     if (sc->mlx_irq == NULL) {
  368: 	device_printf(sc->mlx_dev, "can't allocate interrupt\n");
  369: 	mlx_free(sc);
  370: 	return(ENXIO);
  371:     }
  372:     error = bus_setup_intr(sc->mlx_dev, sc->mlx_irq, INTR_TYPE_BIO | INTR_ENTROPY,  mlx_intr, sc, &sc->mlx_intr);
  373:     if (error) {
  374: 	device_printf(sc->mlx_dev, "can't set up interrupt\n");
  375: 	mlx_free(sc);
  376: 	return(ENXIO);
  377:     }
  378: 
  379:     /*
  380:      * Create DMA tag for mapping buffers into controller-addressable space.
  381:      */
  382:     error = bus_dma_tag_create(sc->mlx_parent_dmat, 		/* parent */
  383: 			       1, 0, 				/* alignment, boundary */
  384: 			       BUS_SPACE_MAXADDR,		/* lowaddr */
  385: 			       BUS_SPACE_MAXADDR, 		/* highaddr */
  386: 			       NULL, NULL, 			/* filter, filterarg */
  387: 			       MAXBSIZE, MLX_NSEG,		/* maxsize, nsegments */
  388: 			       BUS_SPACE_MAXSIZE_32BIT,		/* maxsegsize */
  389: 			       0,				/* flags */
  390: 			       &sc->mlx_buffer_dmat);
  391:     if (error != 0) {
  392: 	device_printf(sc->mlx_dev, "can't allocate buffer DMA tag\n");
  393: 	mlx_free(sc);
  394: 	return(ENOMEM);
  395:     }
  396: 
  397:     /*
  398:      * Create some initial scatter/gather mappings so we can run the probe commands.
  399:      */
  400:     error = mlx_sglist_map(sc);
  401:     if (error != 0) {
  402: 	device_printf(sc->mlx_dev, "can't make initial s/g list mapping\n");
  403: 	mlx_free(sc);
  404: 	return(error);
  405:     }
  406: 
  407:     /*
  408:      * We don't (yet) know where the event log is up to.
  409:      */
  410:     sc->mlx_currevent = -1;
  411: 
  412:     /* 
  413:      * Obtain controller feature information
  414:      */
  415:     if ((sc->mlx_enq2 = mlx_enquire(sc, MLX_CMD_ENQUIRY2, sizeof(struct mlx_enquiry2), NULL)) == NULL) {
  416: 	device_printf(sc->mlx_dev, "ENQUIRY2 failed\n");
  417: 	mlx_free(sc);
  418: 	return(ENXIO);
  419:     }
  420: 
  421:     /*
  422:      * Do quirk/feature related things.
  423:      */
  424:     fwminor = (sc->mlx_enq2->me_firmware_id >> 8) & 0xff;
  425:     switch(sc->mlx_iftype) {
  426:     case MLX_IFTYPE_2:
  427: 	/* These controllers don't report the firmware version in the ENQUIRY2 response */
  428: 	if ((meo = mlx_enquire(sc, MLX_CMD_ENQUIRY_OLD, sizeof(struct mlx_enquiry_old), NULL)) == NULL) {
  429: 	    device_printf(sc->mlx_dev, "ENQUIRY_OLD failed\n");
  430: 	    mlx_free(sc);
  431: 	    return(ENXIO);
  432: 	}
  433: 	sc->mlx_enq2->me_firmware_id = ('0' << 24) | (0 << 16) | (meo->me_fwminor << 8) | meo->me_fwmajor;
  434: 	free(meo, M_DEVBUF);
  435: 	
  436: 	/* XXX require 2.42 or better (PCI) or 2.14 or better (EISA) */
  437: 	if (meo->me_fwminor < 42) {
  438: 	    device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n");
  439: 	    device_printf(sc->mlx_dev, " *** WARNING *** Use revision 2.42 or later\n");
  440: 	}
  441: 	break;
  442:     case MLX_IFTYPE_3:
  443: 	/* XXX certify 3.52? */
  444: 	if (fwminor < 51) {
  445: 	    device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n");
  446: 	    device_printf(sc->mlx_dev, " *** WARNING *** Use revision 3.51 or later\n");
  447: 	}
  448: 	break;
  449:     case MLX_IFTYPE_4:
  450: 	/* XXX certify firmware versions? */
  451: 	if (fwminor < 6) {
  452: 	    device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n");
  453: 	    device_printf(sc->mlx_dev, " *** WARNING *** Use revision 4.06 or later\n");
  454: 	}
  455: 	break;
  456:     case MLX_IFTYPE_5:
  457: 	if (fwminor < 7) {
  458: 	    device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n");
  459: 	    device_printf(sc->mlx_dev, " *** WARNING *** Use revision 5.07 or later\n");
  460: 	}
  461: 	break;
  462:     default:
  463: 	mlx_free(sc);
  464: 	return(ENXIO);		/* should never happen */
  465:     }
  466: 
  467:     /*
  468:      * Create the final scatter/gather mappings now that we have characterised the controller.
  469:      */
  470:     error = mlx_sglist_map(sc);
  471:     if (error != 0) {
  472: 	device_printf(sc->mlx_dev, "can't make final s/g list mapping\n");
  473: 	mlx_free(sc);
  474: 	return(error);
  475:     }
  476: 
  477:     /*
  478:      * No user-requested background operation is in progress.
  479:      */
  480:     sc->mlx_background = 0;
  481:     sc->mlx_rebuildstat.rs_code = MLX_REBUILDSTAT_IDLE;
  482: 
  483:     /*
  484:      * Create the control device.
  485:      */
  486:     sc->mlx_dev_t = make_dev(&mlx_cdevsw, device_get_unit(sc->mlx_dev), UID_ROOT, GID_OPERATOR, 
  487: 			     S_IRUSR | S_IWUSR, "mlx%d", device_get_unit(sc->mlx_dev));
  488: 
  489:     /*
  490:      * Start the timeout routine.
  491:      */
  492:     sc->mlx_timeout = timeout(mlx_periodic, sc, hz);
  493: 
  494:     /* print a little information about the controller */
  495:     mlx_describe_controller(sc);
  496: 
  497:     return(0);
  498: }
  499: 
  500: /********************************************************************************
  501:  * Locate disk resources and attach children to them.
  502:  */
  503: void
  504: mlx_startup(struct mlx_softc *sc)
  505: {
  506:     struct mlx_enq_sys_drive	*mes;
  507:     struct mlx_sysdrive		*dr;
  508:     int				i, error;
  509: 
  510:     debug_called(1);
  511:     
  512:     /*
  513:      * Scan all the system drives and attach children for those that
  514:      * don't currently have them.
  515:      */
  516:     mes = mlx_enquire(sc, MLX_CMD_ENQSYSDRIVE, sizeof(*mes) * MLX_MAXDRIVES, NULL);
  517:     if (mes == NULL) {
  518: 	device_printf(sc->mlx_dev, "error fetching drive status\n");
  519: 	return;
  520:     }
  521:     
  522:     /* iterate over drives returned */
  523:     for (i = 0, dr = &sc->mlx_sysdrive[0];
  524: 	 (i < MLX_MAXDRIVES) && (mes[i].sd_size != 0xffffffff);
  525: 	 i++, dr++) {
  526: 	/* are we already attached to this drive? */
  527:     	if (dr->ms_disk == 0) {
  528: 	    /* pick up drive information */
  529: 	    dr->ms_size = mes[i].sd_size;
  530: 	    dr->ms_raidlevel = mes[i].sd_raidlevel & 0xf;
  531: 	    dr->ms_state = mes[i].sd_state;
  532: 
  533: 	    /* generate geometry information */
  534: 	    if (sc->mlx_geom == MLX_GEOM_128_32) {
  535: 		dr->ms_heads = 128;
  536: 		dr->ms_sectors = 32;
  537: 		dr->ms_cylinders = dr->ms_size / (128 * 32);
  538: 	    } else {        /* MLX_GEOM_255/63 */
  539: 		dr->ms_heads = 255;
  540: 		dr->ms_sectors = 63;
  541: 		dr->ms_cylinders = dr->ms_size / (255 * 63);
  542: 	    }
  543: 	    dr->ms_disk =  device_add_child(sc->mlx_dev, /*"mlxd"*/NULL, -1);
  544: 	    if (dr->ms_disk == 0)
  545: 		device_printf(sc->mlx_dev, "device_add_child failed\n");
  546: 	    device_set_ivars(dr->ms_disk, dr);
  547: 	}
  548:     }
  549:     free(mes, M_DEVBUF);
  550:     if ((error = bus_generic_attach(sc->mlx_dev)) != 0)
  551: 	device_printf(sc->mlx_dev, "bus_generic_attach returned %d", error);
  552: 
  553:     /* mark controller back up */
  554:     sc->mlx_state &= ~MLX_STATE_SHUTDOWN;
  555: 
  556:     /* enable interrupts */
  557:     sc->mlx_intaction(sc, MLX_INTACTION_ENABLE);
  558: }
  559: 
  560: /********************************************************************************
  561:  * Disconnect from the controller completely, in preparation for unload.
  562:  */
  563: int
  564: mlx_detach(device_t dev)
  565: {
  566:     struct mlx_softc	*sc = device_get_softc(dev);
  567:     struct mlxd_softc	*mlxd;
  568:     int			i, s, error;
  569: 
  570:     debug_called(1);
  571: 
  572:     error = EBUSY;
  573:     s = splbio();
  574:     if (sc->mlx_state & MLX_STATE_OPEN)
  575: 	goto out;
  576: 
  577:     for (i = 0; i < MLX_MAXDRIVES; i++) {
  578: 	if (sc->mlx_sysdrive[i].ms_disk != 0) {
  579: 	    mlxd = device_get_softc(sc->mlx_sysdrive[i].ms_disk);
  580: 	    if (mlxd->mlxd_flags & MLXD_OPEN) {		/* drive is mounted, abort detach */
  581: 		device_printf(sc->mlx_sysdrive[i].ms_disk, "still open, can't detach\n");
  582: 		goto out;
  583: 	    }
  584: 	}
  585:     }
  586:     if ((error = mlx_shutdown(dev)))
  587: 	goto out;
  588: 
  589:     mlx_free(sc);
  590: 
  591:     error = 0;
  592:  out:
  593:     splx(s);
  594:     return(error);
  595: }
  596: 
  597: /********************************************************************************
  598:  * Bring the controller down to a dormant state and detach all child devices.
  599:  *
  600:  * This function is called before detach, system shutdown, or before performing
  601:  * an operation which may add or delete system disks.  (Call mlx_startup to
  602:  * resume normal operation.)
  603:  *
  604:  * Note that we can assume that the bioq on the controller is empty, as we won't
  605:  * allow shutdown if any device is open.
  606:  */
  607: int
  608: mlx_shutdown(device_t dev)
  609: {
  610:     struct mlx_softc	*sc = device_get_softc(dev);
  611:     int			i, s, error;
  612: 
  613:     debug_called(1);
  614: 
  615:     s = splbio();
  616:     error = 0;
  617: 
  618:     sc->mlx_state |= MLX_STATE_SHUTDOWN;
  619:     sc->mlx_intaction(sc, MLX_INTACTION_DISABLE);
  620: 
  621:     /* flush controller */
  622:     device_printf(sc->mlx_dev, "flushing cache...");
  623:     if (mlx_flush(sc)) {
  624: 	printf("failed\n");
  625:     } else {
  626: 	printf("done\n");
  627:     }
  628:     
  629:     /* delete all our child devices */
  630:     for (i = 0; i < MLX_MAXDRIVES; i++) {
  631: 	if (sc->mlx_sysdrive[i].ms_disk != 0) {
  632: 	    if ((error = device_delete_child(sc->mlx_dev, sc->mlx_sysdrive[i].ms_disk)) != 0)
  633: 		goto out;
  634: 	    sc->mlx_sysdrive[i].ms_disk = 0;
  635: 	}
  636:     }
  637: 
  638:  out:
  639:     splx(s);
  640:     return(error);
  641: }
  642: 
  643: /********************************************************************************
  644:  * Bring the controller to a quiescent state, ready for system suspend.
  645:  */
  646: int
  647: mlx_suspend(device_t dev)
  648: {
  649:     struct mlx_softc	*sc = device_get_softc(dev);
  650:     int			s;
  651: 
  652:     debug_called(1);
  653: 
  654:     s = splbio();
  655:     sc->mlx_state |= MLX_STATE_SUSPEND;
  656:     
  657:     /* flush controller */
  658:     device_printf(sc->mlx_dev, "flushing cache...");
  659:     printf("%s\n", mlx_flush(sc) ? "failed" : "done");
  660: 
  661:     sc->mlx_intaction(sc, MLX_INTACTION_DISABLE);
  662:     splx(s);
  663: 
  664:     return(0);
  665: }
  666: 
  667: /********************************************************************************
  668:  * Bring the controller back to a state ready for operation.
  669:  */
  670: int
  671: mlx_resume(device_t dev)
  672: {
  673:     struct mlx_softc	*sc = device_get_softc(dev);
  674: 
  675:     debug_called(1);
  676: 
  677:     sc->mlx_state &= ~MLX_STATE_SUSPEND;
  678:     sc->mlx_intaction(sc, MLX_INTACTION_ENABLE);
  679: 
  680:     return(0);
  681: }
  682: 
  683: /*******************************************************************************
  684:  * Take an interrupt, or be poked by other code to look for interrupt-worthy
  685:  * status.
  686:  */
  687: void
  688: mlx_intr(void *arg)
  689: {
  690:     struct mlx_softc	*sc = (struct mlx_softc *)arg;
  691: 
  692:     debug_called(1);
  693: 
  694:     /* collect finished commands, queue anything waiting */
  695:     mlx_done(sc);
  696: };
  697: 
  698: /*******************************************************************************
  699:  * Receive a buf structure from a child device and queue it on a particular
  700:  * disk resource, then poke the disk resource to start as much work as it can.
  701:  */
  702: int
  703: mlx_submit_buf(struct mlx_softc *sc, mlx_bio *bp)
  704: {
  705:     int		s;
  706:     
  707:     debug_called(1);
  708: 
  709:     s = splbio();
  710:     MLX_BIO_QINSERT(sc->mlx_bioq, bp);
  711:     sc->mlx_waitbufs++;
  712:     splx(s);
  713:     mlx_startio(sc);
  714:     return(0);
  715: }
  716: 
  717: /********************************************************************************
  718:  * Accept an open operation on the control device.
  719:  */
  720: int
  721: mlx_open(dev_t dev, int flags, int fmt, d_thread_t *td)
  722: {
  723:     int			unit = minor(dev);
  724:     struct mlx_softc	*sc = devclass_get_softc(mlx_devclass, unit);
  725: 
  726:     sc->mlx_state |= MLX_STATE_OPEN;
  727:     return(0);
  728: }
  729: 
  730: /********************************************************************************
  731:  * Accept the last close on the control device.
  732:  */
  733: int
  734: mlx_close(dev_t dev, int flags, int fmt, d_thread_t *td)
  735: {
  736:     int			unit = minor(dev);
  737:     struct mlx_softc	*sc = devclass_get_softc(mlx_devclass, unit);
  738: 
  739:     sc->mlx_state &= ~MLX_STATE_OPEN;
  740:     return (0);
  741: }
  742: 
  743: /********************************************************************************
  744:  * Handle controller-specific control operations.
  745:  */
  746: int
  747: mlx_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *td)
  748: {
  749:     int				unit = minor(dev);
  750:     struct mlx_softc		*sc = devclass_get_softc(mlx_devclass, unit);
  751:     struct mlx_rebuild_request	*rb = (struct mlx_rebuild_request *)addr;
  752:     struct mlx_rebuild_status	*rs = (struct mlx_rebuild_status *)addr;
  753:     int				*arg = (int *)addr;
  754:     struct mlx_pause		*mp;
  755:     struct mlx_sysdrive		*dr;
  756:     struct mlxd_softc		*mlxd;
  757:     int				i, error;
  758:     
  759:     switch(cmd) {
  760: 	/*
  761: 	 * Enumerate connected system drives; returns the first system drive's
  762: 	 * unit number if *arg is -1, or the next unit after *arg if it's
  763: 	 * a valid unit on this controller.
  764: 	 */
  765:     case MLX_NEXT_CHILD:
  766: 	/* search system drives */
  767: 	for (i = 0; i < MLX_MAXDRIVES; i++) {
  768: 	    /* is this one attached? */
  769: 	    if (sc->mlx_sysdrive[i].ms_disk != 0) {
  770: 		/* looking for the next one we come across? */
  771: 		if (*arg == -1) {
  772: 		    *arg = device_get_unit(sc->mlx_sysdrive[0].ms_disk);
  773: 		    return(0);
  774: 		}
  775: 		/* we want the one after this one */
  776: 		if (*arg == device_get_unit(sc->mlx_sysdrive[i].ms_disk))
  777: 		    *arg = -1;
  778: 	    }
  779: 	}
  780: 	return(ENOENT);
  781: 
  782: 	/*
  783: 	 * Scan the controller to see whether new drives have appeared.
  784: 	 */
  785:     case MLX_RESCAN_DRIVES:
  786: 	mlx_startup(sc);
  787: 	return(0);
  788: 
  789: 	/*
  790: 	 * Disconnect from the specified drive; it may be about to go 
  791: 	 * away.
  792: 	 */
  793:     case MLX_DETACH_DRIVE:			/* detach one drive */
  794: 	
  795: 	if (((dr = mlx_findunit(sc, *arg)) == NULL) || 
  796: 	    ((mlxd = device_get_softc(dr->ms_disk)) == NULL))
  797: 	    return(ENOENT);
  798: 
  799: 	device_printf(dr->ms_disk, "detaching...");
  800: 	error = 0;
  801: 	if (mlxd->mlxd_flags & MLXD_OPEN) {
  802: 	    error = EBUSY;
  803: 	    goto detach_out;
  804: 	}
  805: 	
  806: 	/* flush controller */
  807: 	if (mlx_flush(sc)) {
  808: 	    error = EBUSY;
  809: 	    goto detach_out;
  810: 	}
  811: 
  812: 	/* nuke drive */
  813: 	if ((error = device_delete_child(sc->mlx_dev, dr->ms_disk)) != 0)
  814: 	    goto detach_out;
  815: 	dr->ms_disk = 0;
  816: 
  817:     detach_out:
  818: 	if (error) {
  819: 	    printf("failed\n");
  820: 	} else {
  821: 	    printf("done\n");
  822: 	}
  823: 	return(error);
  824: 
  825: 	/*
  826: 	 * Pause one or more SCSI channels for a period of time, to assist
  827: 	 * in the process of hot-swapping devices.
  828: 	 *
  829: 	 * Note that at least the 3.51 firmware on the DAC960PL doesn't seem
  830: 	 * to do this right.
  831: 	 */
  832:     case MLX_PAUSE_CHANNEL:			/* schedule a channel pause */
  833: 	/* Does this command work on this firmware? */
  834: 	if (!(sc->mlx_feature & MLX_FEAT_PAUSEWORKS))
  835: 	    return(EOPNOTSUPP);
  836: 
  837: 	mp = (struct mlx_pause *)addr;
  838: 	if ((mp->mp_which == MLX_PAUSE_CANCEL) && (sc->mlx_pause.mp_when != 0)) {
  839: 	    /* cancel a pending pause operation */
  840: 	    sc->mlx_pause.mp_which = 0;
  841: 	} else {
  842: 	    /* fix for legal channels */
  843: 	    mp->mp_which &= ((1 << sc->mlx_enq2->me_actual_channels) -1);
  844: 	    /* check time values */
  845: 	    if ((mp->mp_when < 0) || (mp->mp_when > 3600))
  846: 		return(EINVAL);
  847: 	    if ((mp->mp_howlong < 1) || (mp->mp_howlong > (0xf * 30)))
  848: 		return(EINVAL);
  849: 	    
  850: 	    /* check for a pause currently running */
  851: 	    if ((sc->mlx_pause.mp_which != 0) && (sc->mlx_pause.mp_when == 0))
  852: 		return(EBUSY);
  853: 
  854: 	    /* looks ok, go with it */
  855: 	    sc->mlx_pause.mp_which = mp->mp_which;
  856: 	    sc->mlx_pause.mp_when = time_second + mp->mp_when;
  857: 	    sc->mlx_pause.mp_howlong = sc->mlx_pause.mp_when + mp->mp_howlong;
  858: 	}
  859: 	return(0);
  860: 
  861: 	/*
  862: 	 * Accept a command passthrough-style.
  863: 	 */
  864:     case MLX_COMMAND:
  865: 	return(mlx_user_command(sc, (struct mlx_usercommand *)addr));
  866: 
  867: 	/*
  868: 	 * Start a rebuild on a given SCSI disk
  869: 	 */
  870:     case MLX_REBUILDASYNC:
  871: 	if (sc->mlx_background != 0) {
  872: 	    rb->rr_status = 0x0106;
  873: 	    return(EBUSY);
  874: 	}
  875: 	rb->rr_status = mlx_rebuild(sc, rb->rr_channel, rb->rr_target);
  876: 	switch (rb->rr_status) {
  877: 	case 0:
  878: 	    error = 0;
  879: 	    break;
  880: 	case 0x10000:
  881: 	    error = ENOMEM;		/* couldn't set up the command */
  882: 	    break;
  883: 	case 0x0002:	
  884: 	    error = EBUSY;
  885: 	    break;
  886: 	case 0x0104:
  887: 	    error = EIO;
  888: 	    break;
  889: 	case 0x0105:
  890: 	    error = ERANGE;
  891: 	    break;
  892: 	case 0x0106:
  893: 	    error = EBUSY;
  894: 	    break;
  895: 	default:
  896: 	    error = EINVAL;
  897: 	    break;
  898: 	}
  899: 	if (error == 0)
  900: 	    sc->mlx_background = MLX_BACKGROUND_REBUILD;
  901: 	return(error);
  902: 	
  903: 	/*
  904: 	 * Get the status of the current rebuild or consistency check.
  905: 	 */
  906:     case MLX_REBUILDSTAT:
  907: 	*rs = sc->mlx_rebuildstat;
  908: 	return(0);
  909: 
  910: 	/*
  911: 	 * Return the per-controller system drive number matching the
  912: 	 * disk device number in (arg), if it happens to belong to us.
  913: 	 */
  914:     case MLX_GET_SYSDRIVE:
  915: 	error = ENOENT;
  916: 	mlxd = (struct mlxd_softc *)devclass_get_softc(mlxd_devclass, *arg);
  917: 	if ((mlxd != NULL) && (mlxd->mlxd_drive >= sc->mlx_sysdrive) && 
  918: 	    (mlxd->mlxd_drive < (sc->mlx_sysdrive + MLX_MAXDRIVES))) {
  919: 	    error = 0;
  920: 	    *arg = mlxd->mlxd_drive - sc->mlx_sysdrive;
  921: 	}
  922: 	return(error);
  923: 	
  924:     default:	
  925: 	return(ENOTTY);
  926:     }
  927: }
  928: 
  929: /********************************************************************************
  930:  * Handle operations requested by a System Drive connected to this controller.
  931:  */
  932: int
  933: mlx_submit_ioctl(struct mlx_softc *sc, struct mlx_sysdrive *drive, u_long cmd, 
  934: 		caddr_t addr, int32_t flag, d_thread_t *td)
  935: {
  936:     int				*arg = (int *)addr;
  937:     int				error, result;
  938: 
  939:     switch(cmd) {
  940: 	/*
  941: 	 * Return the current status of this drive.
  942: 	 */
  943:     case MLXD_STATUS:
  944: 	*arg = drive->ms_state;
  945: 	return(0);
  946: 	
  947: 	/*
  948: 	 * Start a background consistency check on this drive.
  949: 	 */
  950:     case MLXD_CHECKASYNC:		/* start a background consistency check */
  951: 	if (sc->mlx_background != 0) {
  952: 	    *arg = 0x0106;
  953: 	    return(EBUSY);
  954: 	}
  955: 	result = mlx_check(sc, drive - &sc->mlx_sysdrive[0]);
  956: 	switch (result) {
  957: 	case 0:
  958: 	    error = 0;
  959: 	    break;
  960: 	case 0x10000:
  961: 	    error = ENOMEM;		/* couldn't set up the command */
  962: 	    break;
  963: 	case 0x0002:	
  964: 	    error = EIO;
  965: 	    break;
  966: 	case 0x0105:
  967: 	    error = ERANGE;
  968: 	    break;
  969: 	case 0x0106:
  970: 	    error = EBUSY;
  971: 	    break;
  972: 	default:
  973: 	    error = EINVAL;
  974: 	    break;
  975: 	}
  976: 	if (error == 0)
  977: 	    sc->mlx_background = MLX_BACKGROUND_CHECK;
  978: 	*arg = result;
  979: 	return(error);
  980: 
  981:     }
  982:     return(ENOIOCTL);
  983: }
  984: 
  985: 
  986: /********************************************************************************
  987:  ********************************************************************************
  988:                                                                 Status Monitoring
  989:  ********************************************************************************
  990:  ********************************************************************************/
  991: 
  992: /********************************************************************************
  993:  * Fire off commands to periodically check the status of connected drives.
  994:  */
  995: static void
  996: mlx_periodic(void *data)
  997: {
  998:     struct mlx_softc *sc = (struct mlx_softc *)data;
  999: 
 1000:     debug_called(1);
 1001: 
 1002:     /*
 1003:      * Run a bus pause? 
 1004:      */
 1005:     if ((sc->mlx_pause.mp_which != 0) &&
 1006: 	(sc->mlx_pause.mp_when > 0) &&
 1007: 	(time_second >= sc->mlx_pause.mp_when)){
 1008: 
 1009: 	mlx_pause_action(sc);		/* pause is running */
 1010: 	sc->mlx_pause.mp_when = 0;
 1011: 	sysbeep(500, hz);
 1012: 
 1013: 	/* 
 1014: 	 * Bus pause still running?
 1015: 	 */
 1016:     } else if ((sc->mlx_pause.mp_which != 0) &&
 1017: 	       (sc->mlx_pause.mp_when == 0)) {
 1018: 
 1019: 	/* time to stop bus pause? */
 1020: 	if (time_second >= sc->mlx_pause.mp_howlong) {
 1021: 	    mlx_pause_action(sc);
 1022: 	    sc->mlx_pause.mp_which = 0;	/* pause is complete */
 1023: 	    sysbeep(500, hz);
 1024: 	} else {
 1025: 	    sysbeep((time_second % 5) * 100 + 500, hz/8);
 1026: 	}
 1027: 
 1028: 	/* 
 1029: 	 * Run normal periodic activities? 
 1030: 	 */
 1031:     } else if (time_second > (sc->mlx_lastpoll + 10)) {
 1032: 	sc->mlx_lastpoll = time_second;
 1033: 
 1034: 	/* 
 1035: 	 * Check controller status.
 1036: 	 *
 1037: 	 * XXX Note that this may not actually launch a command in situations of high load.
 1038: 	 */
 1039: 	mlx_enquire(sc, (sc->mlx_iftype == MLX_IFTYPE_2) ? MLX_CMD_ENQUIRY_OLD : MLX_CMD_ENQUIRY, 
 1040: 		    imax(sizeof(struct mlx_enquiry), sizeof(struct mlx_enquiry_old)), mlx_periodic_enquiry);
 1041: 
 1042: 	/*
 1043: 	 * Check system drive status.
 1044: 	 *
 1045: 	 * XXX This might be better left to event-driven detection, eg. I/O to an offline
 1046: 	 *     drive will detect it's offline, rebuilds etc. should detect the drive is back
 1047: 	 *     online.
 1048: 	 */
 1049: 	mlx_enquire(sc, MLX_CMD_ENQSYSDRIVE, sizeof(struct mlx_enq_sys_drive) * MLX_MAXDRIVES, 
 1050: 			mlx_periodic_enquiry);
 1051: 		
 1052:     }
 1053: 
 1054:     /* get drive rebuild/check status */
 1055:     /* XXX should check sc->mlx_background if this is only valid while in progress */
 1056:     mlx_enquire(sc, MLX_CMD_REBUILDSTAT, sizeof(struct mlx_rebuild_stat), mlx_periodic_rebuild);
 1057: 
 1058:     /* deal with possibly-missed interrupts and timed-out commands */
 1059:     mlx_done(sc);
 1060: 
 1061:     /* reschedule another poll next second or so */
 1062:     sc->mlx_timeout = timeout(mlx_periodic, sc, hz);
 1063: }
 1064: 
 1065: /********************************************************************************
 1066:  * Handle the result of an ENQUIRY command instigated by periodic status polling.
 1067:  */
 1068: static void
 1069: mlx_periodic_enquiry(struct mlx_command *mc)
 1070: {
 1071:     struct mlx_softc		*sc = mc->mc_sc;
 1072: 
 1073:     debug_called(1);
 1074: 
 1075:     /* Command completed OK? */
 1076:     if (mc->mc_status != 0) {
 1077: 	device_printf(sc->mlx_dev, "periodic enquiry failed - %s\n", mlx_diagnose_command(mc));
 1078: 	goto out;
 1079:     }
 1080: 
 1081:     /* respond to command */
 1082:     switch(mc->mc_mailbox[0]) {
 1083: 	/*
 1084: 	 * This is currently a bit fruitless, as we don't know how to extract the eventlog
 1085: 	 * pointer yet.
 1086: 	 */
 1087:     case MLX_CMD_ENQUIRY_OLD:
 1088:     {
 1089: 	struct mlx_enquiry		*me = (struct mlx_enquiry *)mc->mc_data;
 1090: 	struct mlx_enquiry_old		*meo = (struct mlx_enquiry_old *)mc->mc_data;
 1091: 	int				i;
 1092: 
 1093: 	/* convert data in-place to new format */
 1094: 	for (i = (sizeof(me->me_dead) / sizeof(me->me_dead[0])) - 1; i >= 0; i--) {
 1095: 	    me->me_dead[i].dd_chan = meo->me_dead[i].dd_chan;
 1096: 	    me->me_dead[i].dd_targ = meo->me_dead[i].dd_targ;
 1097: 	}
 1098: 	me->me_misc_flags        = 0;
 1099: 	me->me_rebuild_count     = meo->me_rebuild_count;
 1100: 	me->me_dead_count        = meo->me_dead_count;
 1101: 	me->me_critical_sd_count = meo->me_critical_sd_count;
 1102: 	me->me_event_log_seq_num = 0;
 1103: 	me->me_offline_sd_count  = meo->me_offline_sd_count;
 1104: 	me->me_max_commands      = meo->me_max_commands;
 1105: 	me->me_rebuild_flag      = meo->me_rebuild_flag;
 1106: 	me->me_fwmajor           = meo->me_fwmajor;
 1107: 	me->me_fwminor           = meo->me_fwminor;
 1108: 	me->me_status_flags      = meo->me_status_flags;
 1109: 	me->me_flash_age         = meo->me_flash_age;
 1110: 	for (i = (sizeof(me->me_drvsize) / sizeof(me->me_drvsize[0])) - 1; i >= 0; i--) {
 1111: 	    if (i > ((sizeof(meo->me_drvsize) / sizeof(meo->me_drvsize[0])) - 1)) {
 1112: 		me->me_drvsize[i] = 0;		/* drive beyond supported range */
 1113: 	    } else {
 1114: 		me->me_drvsize[i] = meo->me_drvsize[i];
 1115: 	    }
 1116: 	}
 1117: 	me->me_num_sys_drvs = meo->me_num_sys_drvs;
 1118:     }
 1119:     /* FALLTHROUGH */
 1120: 
 1121: 	/*
 1122: 	 * Generic controller status update.  We could do more with this than just
 1123: 	 * checking the event log.
 1124: 	 */
 1125:     case MLX_CMD_ENQUIRY:
 1126:     {
 1127: 	struct mlx_enquiry		*me = (struct mlx_enquiry *)mc->mc_data;
 1128: 	
 1129: 	if (sc->mlx_currevent == -1) {
 1130: 	    /* initialise our view of the event log */
 1131: 	    sc->mlx_currevent = sc->mlx_lastevent = me->me_event_log_seq_num;
 1132: 	} else if ((me->me_event_log_seq_num != sc->mlx_lastevent) && !(sc->mlx_flags & MLX_EVENTLOG_BUSY)) {
 1133: 	    /* record where current events are up to */
 1134: 	    sc->mlx_currevent = me->me_event_log_seq_num;
 1135: 	    debug(1, "event log pointer was %d, now %d\n", sc->mlx_lastevent, sc->mlx_currevent);
 1136: 
 1137: 	    /* mark the event log as busy */
 1138: 	    atomic_set_int(&sc->mlx_flags, MLX_EVENTLOG_BUSY);
 1139: 	    
 1140: 	    /* drain new eventlog entries */
 1141: 	    mlx_periodic_eventlog_poll(sc);
 1142: 	}
 1143: 	break;
 1144:     }
 1145:     case MLX_CMD_ENQSYSDRIVE:
 1146:     {
 1147: 	struct mlx_enq_sys_drive	*mes = (struct mlx_enq_sys_drive *)mc->mc_data;
 1148: 	struct mlx_sysdrive		*dr;
 1149: 	int				i;
 1150: 	
 1151: 	for (i = 0, dr = &sc->mlx_sysdrive[0]; 
 1152: 	     (i < MLX_MAXDRIVES) && (mes[i].sd_size != 0xffffffff); 
 1153: 	     i++) {
 1154: 
 1155: 	    /* has state been changed by controller? */
 1156: 	    if (dr->ms_state != mes[i].sd_state) {
 1157: 		switch(mes[i].sd_state) {
 1158: 		case MLX_SYSD_OFFLINE:
 1159: 		    device_printf(dr->ms_disk, "drive offline\n");
 1160: 		    break;
 1161: 		case MLX_SYSD_ONLINE:
 1162: 		    device_printf(dr->ms_disk, "drive online\n");
 1163: 		    break;
 1164: 		case MLX_SYSD_CRITICAL:
 1165: 		    device_printf(dr->ms_disk, "drive critical\n");
 1166: 		    break;
 1167: 		}
 1168: 		/* save new state */
 1169: 		dr->ms_state = mes[i].sd_state;
 1170: 	    }
 1171: 	}
 1172: 	break;
 1173:     }
 1174:     default:
 1175: 	device_printf(sc->mlx_dev, "%s: unknown command 0x%x", __FUNCTION__, mc->mc_mailbox[0]);
 1176: 	break;
 1177:     }
 1178: 
 1179:  out:
 1180:     free(mc->mc_data, M_DEVBUF);
 1181:     mlx_releasecmd(mc);
 1182: }
 1183: 
 1184: /********************************************************************************
 1185:  * Instigate a poll for one event log message on (sc).
 1186:  * We only poll for one message at a time, to keep our command usage down.
 1187:  */
 1188: static void
 1189: mlx_periodic_eventlog_poll(struct mlx_softc *sc)
 1190: {
 1191:     struct mlx_command	*mc;
 1192:     void		*result = NULL;
 1193:     int			error;
 1194: 
 1195:     debug_called(1);
 1196: 
 1197:     /* get ourselves a command buffer */
 1198:     error = 1;
 1199:     if ((mc = mlx_alloccmd(sc)) == NULL)
 1200: 	goto out;
 1201:     /* allocate the response structure */
 1202:     if ((result = malloc(/*sizeof(struct mlx_eventlog_entry)*/1024, M_DEVBUF, M_NOWAIT)) == NULL)
 1203: 	goto out;
 1204:     /* get a command slot */
 1205:     if (mlx_getslot(mc))
 1206: 	goto out;
 1207: 
 1208:     /* map the command so the controller can see it */
 1209:     mc->mc_data = result;
 1210:     mc->mc_length = /*sizeof(struct mlx_eventlog_entry)*/1024;
 1211:     mlx_mapcmd(mc);
 1212: 
 1213:     /* build the command to get one entry */
 1214:     mlx_make_type3(mc, MLX_CMD_LOGOP, MLX_LOGOP_GET, 1, sc->mlx_lastevent, 0, 0, mc->mc_dataphys, 0);
 1215:     mc->mc_complete = mlx_periodic_eventlog_respond;
 1216:     mc->mc_private = mc;
 1217: 
 1218:     /* start the command */
 1219:     if ((error = mlx_start(mc)) != 0)
 1220: 	goto out;
 1221:     
 1222:     error = 0;			/* success */
 1223:  out:
 1224:     if (error != 0) {
 1225: 	if (mc != NULL)
 1226: 	    mlx_releasecmd(mc);
 1227: 	if (result != NULL)
 1228: 	    free(result, M_DEVBUF);
 1229:     }
 1230: }
 1231: 
 1232: /********************************************************************************
 1233:  * Handle the result of polling for a log message, generate diagnostic output.
 1234:  * If this wasn't the last message waiting for us, we'll go collect another.
 1235:  */
 1236: static char *mlx_sense_messages[] = {
 1237:     "because write recovery failed",
 1238:     "because of SCSI bus reset failure",
 1239:     "because of double check condition",
 1240:     "because it was removed",
 1241:     "because of gross error on SCSI chip",
 1242:     "because of bad tag returned from drive",
 1243:     "because of timeout on SCSI command",
 1244:     "because of reset SCSI command issued from system",
 1245:     "because busy or parity error count exceeded limit",
 1246:     "because of 'kill drive' command from system",
 1247:     "because of selection timeout",
 1248:     "due to SCSI phase sequence error",
 1249:     "due to unknown status"
 1250: };
 1251: 
 1252: static void
 1253: mlx_periodic_eventlog_respond(struct mlx_command *mc)
 1254: {
 1255:     struct mlx_softc		*sc = mc->mc_sc;
 1256:     struct mlx_eventlog_entry	*el = (struct mlx_eventlog_entry *)mc->mc_data;
 1257:     char			*reason;
 1258: 
 1259:     debug_called(1);
 1260: 
 1261:     sc->mlx_lastevent++;		/* next message... */
 1262:     if (mc->mc_status == 0) {
 1263: 
 1264: 	/* handle event log message */
 1265: 	switch(el->el_type) {
 1266: 	    /*
 1267: 	     * This is the only sort of message we understand at the moment.
 1268: 	     * The tests here are probably incomplete.
 1269: 	     */
 1270: 	case MLX_LOGMSG_SENSE:	/* sense data */
 1271: 	    /* Mylex vendor-specific message indicating a drive was killed? */
 1272: 	    if ((el->el_sensekey == 9) &&
 1273: 		(el->el_asc == 0x80)) {
 1274: 		if (el->el_asq < (sizeof(mlx_sense_messages) / sizeof(mlx_sense_messages[0]))) {
 1275: 		    reason = mlx_sense_messages[el->el_asq];
 1276: 		} else {
 1277: 		    reason = "for unknown reason";
 1278: 		}
 1279: 		device_printf(sc->mlx_dev, "physical drive %d:%d killed %s\n",
 1280: 			      el->el_channel, el->el_target, reason);
 1281: 	    }
 1282: 	    /* SCSI drive was reset? */
 1283: 	    if ((el->el_sensekey == 6) && (el->el_asc == 0x29)) {
 1284: 		device_printf(sc->mlx_dev, "physical drive %d:%d reset\n", 
 1285: 			      el->el_channel, el->el_target);
 1286: 	    }
 1287: 	    /* SCSI drive error? */
 1288: 	    if (!((el->el_sensekey == 0) ||
 1289: 		  ((el->el_sensekey == 2) &&
 1290: 		   (el->el_asc == 0x04) &&
 1291: 		   ((el->el_asq == 0x01) ||
 1292: 		    (el->el_asq == 0x02))))) {
 1293: 		device_printf(sc->mlx_dev, "physical drive %d:%d error log: sense = %d asc = %x asq = %x\n",
 1294: 			      el->el_channel, el->el_target, el->el_sensekey, el->el_asc, el->el_asq);
 1295: 		device_printf(sc->mlx_dev, "  info %4D csi %4D\n", el->el_information, ":", el->el_csi, ":");
 1296: 	    }
 1297: 	    break;
 1298: 	    
 1299: 	default:
 1300: 	    device_printf(sc->mlx_dev, "unknown log message type 0x%x\n", el->el_type);
 1301: 	    break;
 1302: 	}
 1303:     } else {
 1304: 	device_printf(sc->mlx_dev, "error reading message log - %s\n", mlx_diagnose_command(mc));
 1305: 	/* give up on all the outstanding messages, as we may have come unsynched */
 1306: 	sc->mlx_lastevent = sc->mlx_currevent;
 1307:     }
 1308: 	
 1309:     /* dispose of command and data */
 1310:     free(mc->mc_data, M_DEVBUF);
 1311:     mlx_releasecmd(mc);
 1312: 
 1313:     /* is there another message to obtain? */
 1314:     if (sc->mlx_lastevent != sc->mlx_currevent) {
 1315: 	mlx_periodic_eventlog_poll(sc);
 1316:     } else {
 1317: 	/* clear log-busy status */
 1318: 	atomic_clear_int(&sc->mlx_flags, MLX_EVENTLOG_BUSY);
 1319:     }
 1320: }
 1321: 
 1322: /********************************************************************************
 1323:  * Handle check/rebuild operations in progress.
 1324:  */
 1325: static void
 1326: mlx_periodic_rebuild(struct mlx_command *mc)
 1327: {
 1328:     struct mlx_softc		*sc = mc->mc_sc;
 1329:     struct mlx_rebuild_status	*mr = (struct mlx_rebuild_status *)mc->mc_data;
 1330: 
 1331:     switch(mc->mc_status) {
 1332:     case 0:				/* operation running, update stats */
 1333: 	sc->mlx_rebuildstat = *mr;
 1334: 
 1335: 	/* spontaneous rebuild/check? */
 1336: 	if (sc->mlx_background == 0) {
 1337: 	    sc->mlx_background = MLX_BACKGROUND_SPONTANEOUS;
 1338: 	    device_printf(sc->mlx_dev, "background check/rebuild operation started\n");
 1339: 	}
 1340: 	break;
 1341: 
 1342:     case 0x0105:			/* nothing running, finalise stats and report */
 1343: 	switch(sc->mlx_background) {
 1344: 	case MLX_BACKGROUND_CHECK:
 1345: 	    device_printf(sc->mlx_dev, "consistency check completed\n");	/* XXX print drive? */
 1346: 	    break;
 1347: 	case MLX_BACKGROUND_REBUILD:
 1348: 	    device_printf(sc->mlx_dev, "drive rebuild completed\n");	/* XXX print channel/target? */
 1349: 	    break;
 1350: 	case MLX_BACKGROUND_SPONTANEOUS:
 1351: 	default:
 1352: 	    /* if we have previously been non-idle, report the transition */
 1353: 	    if (sc->mlx_rebuildstat.rs_code != MLX_REBUILDSTAT_IDLE) {
 1354: 		device_printf(sc->mlx_dev, "background check/rebuild operation completed\n");
 1355: 	    }
 1356: 	}
 1357: 	sc->mlx_background = 0;
 1358: 	sc->mlx_rebuildstat.rs_code = MLX_REBUILDSTAT_IDLE;
 1359: 	break;
 1360:     }
 1361:     free(mc->mc_data, M_DEVBUF);
 1362:     mlx_releasecmd(mc);
 1363: }
 1364: 
 1365: /********************************************************************************
 1366:  ********************************************************************************
 1367:                                                                     Channel Pause
 1368:  ********************************************************************************
 1369:  ********************************************************************************/
 1370: 
 1371: /********************************************************************************
 1372:  * It's time to perform a channel pause action for (sc), either start or stop
 1373:  * the pause.
 1374:  */
 1375: static void
 1376: mlx_pause_action(struct mlx_softc *sc)
 1377: {
 1378:     struct mlx_command	*mc;
 1379:     int			failsafe, i, command;
 1380: 
 1381:     /* What are we doing here? */
 1382:     if (sc->mlx_pause.mp_when == 0) {
 1383: 	command = MLX_CMD_STARTCHANNEL;
 1384: 	failsafe = 0;
 1385: 
 1386:     } else {
 1387: 	command = MLX_CMD_STOPCHANNEL;
 1388: 
 1389: 	/* 
 1390: 	 * Channels will always start again after the failsafe period, 
 1391: 	 * which is specified in multiples of 30 seconds.
 1392: 	 * This constrains us to a maximum pause of 450 seconds.
 1393: 	 */
 1394: 	failsafe = ((sc->mlx_pause.mp_howlong - time_second) + 5) / 30;
 1395: 	if (failsafe > 0xf) {
 1396: 	    failsafe = 0xf;
 1397: 	    sc->mlx_pause.mp_howlong = time_second + (0xf * 30) - 5;
 1398: 	}
 1399:     }
 1400: 
 1401:     /* build commands for every channel requested */
 1402:     for (i = 0; i < sc->mlx_enq2->me_actual_channels; i++) {
 1403: 	if ((1 << i) & sc->mlx_pause.mp_which) {
 1404: 
 1405: 	    /* get ourselves a command buffer */
 1406: 	    if ((mc = mlx_alloccmd(sc)) == NULL)
 1407: 		goto fail;
 1408: 	    /* get a command slot */
 1409: 	    mc->mc_flags |= MLX_CMD_PRIORITY;
 1410: 	    if (mlx_getslot(mc))
 1411: 		goto fail;
 1412: 
 1413: 	    /* build the command */
 1414: 	    mlx_make_type2(mc, command, (failsafe << 4) | i, 0, 0, 0, 0, 0, 0, 0);
 1415: 	    mc->mc_complete = mlx_pause_done;
 1416: 	    mc->mc_private = sc;		/* XXX not needed */
 1417: 	    if (mlx_start(mc))
 1418: 		goto fail;
 1419: 	    /* command submitted OK */
 1420: 	    return;
 1421:     
 1422: 	fail:
 1423: 	    device_printf(sc->mlx_dev, "%s failed for channel %d\n", 
 1424: 			  command == MLX_CMD_STOPCHANNEL ? "pause" : "resume", i);
 1425: 	    if (mc != NULL)
 1426: 		mlx_releasecmd(mc);
 1427: 	}
 1428:     }
 1429: }
 1430: 
 1431: static void
 1432: mlx_pause_done(struct mlx_command *mc)
 1433: {
 1434:     struct mlx_softc	*sc = mc->mc_sc;
 1435:     int			command = mc->mc_mailbox[0];
 1436:     int			channel = mc->mc_mailbox[2] & 0xf;
 1437:     
 1438:     if (mc->mc_status != 0) {
 1439: 	device_printf(sc->mlx_dev, "%s command failed - %s\n", 
 1440: 		      command == MLX_CMD_STOPCHANNEL ? "pause" : "resume", mlx_diagnose_command(mc));
 1441:     } else if (command == MLX_CMD_STOPCHANNEL) {
 1442: 	device_printf(sc->mlx_dev, "channel %d pausing for %ld seconds\n", 
 1443: 		      channel, (long)(sc->mlx_pause.mp_howlong - time_second));
 1444:     } else {
 1445: 	device_printf(sc->mlx_dev, "channel %d resuming\n", channel);
 1446:     }
 1447:     mlx_releasecmd(mc);
 1448: }
 1449: 
 1450: /********************************************************************************
 1451:  ********************************************************************************
 1452:                                                                Command Submission
 1453:  ********************************************************************************
 1454:  ********************************************************************************/
 1455: 
 1456: /********************************************************************************
 1457:  * Perform an Enquiry command using a type-3 command buffer and a return a single
 1458:  * linear result buffer.  If the completion function is specified, it will
 1459:  * be called with the completed command (and the result response will not be
 1460:  * valid until that point).  Otherwise, the command will either be busy-waited
 1461:  * for (interrupts not enabled), or slept for.
 1462:  */
 1463: static void *
 1464: mlx_enquire(struct mlx_softc *sc, int command, size_t bufsize, void (* complete)(struct mlx_command *mc))
 1465: {
 1466:     struct mlx_command	*mc;
 1467:     void		*result;
 1468:     int			error;
 1469: 
 1470:     debug_called(1);
 1471: 
 1472:     /* get ourselves a command buffer */
 1473:     error = 1;
 1474:     result = NULL;
 1475:     if ((mc = mlx_alloccmd(sc)) == NULL)
 1476: 	goto out;
 1477:     /* allocate the response structure */
 1478:     if ((result = malloc(bufsize, M_DEVBUF, M_NOWAIT)) == NULL)
 1479: 	goto out;
 1480:     /* get a command slot */
 1481:     mc->mc_flags |= MLX_CMD_PRIORITY | MLX_CMD_DATAOUT;
 1482:     if (mlx_getslot(mc))
 1483: 	goto out;
 1484: 
 1485:     /* map the command so the controller can see it */
 1486:     mc->mc_data = result;
 1487:     mc->mc_length = bufsize;
 1488:     mlx_mapcmd(mc);
 1489: 
 1490:     /* build an enquiry command */
 1491:     mlx_make_type2(mc, command, 0, 0, 0, 0, 0, 0, mc->mc_dataphys, 0);
 1492: 
 1493:     /* do we want a completion callback? */
 1494:     if (complete != NULL) {
 1495: 	mc->mc_complete = complete;
 1496: 	mc->mc_private = mc;
 1497: 	if ((error = mlx_start(mc)) != 0)
 1498: 	    goto out;
 1499:     } else {
 1500: 	/* run the command in either polled or wait mode */
 1501: 	if ((sc->mlx_state & MLX_STATE_INTEN) ? mlx_wait_command(mc) : mlx_poll_command(mc))
 1502: 	    goto out;
 1503:     
 1504: 	/* command completed OK? */
 1505: 	if (mc->mc_status != 0) {
 1506: 	    device_printf(sc->mlx_dev, "ENQUIRY failed - %s\n", mlx_diagnose_command(mc));
 1507: 	    goto out;
 1508: 	}
 1509:     }
 1510:     error = 0;			/* success */
 1511:  out:
 1512:     /* we got a command, but nobody else will free it */
 1513:     if ((complete == NULL) && (mc != NULL))
 1514: 	mlx_releasecmd(mc);
 1515:     /* we got an error, and we allocated a result */
 1516:     if ((error != 0) && (result != NULL)) {
 1517: 	free(result, M_DEVBUF);
 1518: 	result = NULL;
 1519:     }
 1520:     return(result);
 1521: }
 1522: 
 1523: 
 1524: /********************************************************************************
 1525:  * Perform a Flush command on the nominated controller.
 1526:  *
 1527:  * May be called with interrupts enabled or disabled; will not return until
 1528:  * the flush operation completes or fails.
 1529:  */
 1530: static int
 1531: mlx_flush(struct mlx_softc *sc)
 1532: {
 1533:     struct mlx_command	*mc;
 1534:     int			error;
 1535: 
 1536:     debug_called(1);
 1537: 
 1538:     /* get ourselves a command buffer */
 1539:     error = 1;
 1540:     if ((mc = mlx_alloccmd(sc)) == NULL)
 1541: 	goto out;
 1542:     /* get a command slot */
 1543:     if (mlx_getslot(mc))
 1544: 	goto out;
 1545: 
 1546:     /* build a flush command */
 1547:     mlx_make_type2(mc, MLX_CMD_FLUSH, 0, 0, 0, 0, 0, 0, 0, 0);
 1548: 
 1549:     /* can't assume that interrupts are going to work here, so play it safe */
 1550:     if (mlx_poll_command(mc))
 1551: 	goto out;
 1552:     
 1553:     /* command completed OK? */
 1554:     if (mc->mc_status != 0) {
 1555: 	device_printf(sc->mlx_dev, "FLUSH failed - %s\n", mlx_diagnose_command(mc));
 1556: 	goto out;
 1557:     }
 1558:     
 1559:     error = 0;			/* success */
 1560:  out:
 1561:     if (mc != NULL)
 1562: 	mlx_releasecmd(mc);
 1563:     return(error);
 1564: }
 1565: 
 1566: /********************************************************************************
 1567:  * Start a background consistency check on (drive).
 1568:  *
 1569:  * May be called with interrupts enabled or disabled; will return as soon as the
 1570:  * operation has started or been refused.
 1571:  */
 1572: static int
 1573: mlx_check(struct mlx_softc *sc, int drive)
 1574: {
 1575:     struct mlx_command	*mc;
 1576:     int			error;
 1577: 
 1578:     debug_called(1);
 1579: 
 1580:     /* get ourselves a command buffer */
 1581:     error = 0x10000;
 1582:     if ((mc = mlx_alloccmd(sc)) == NULL)
 1583: 	goto out;
 1584:     /* get a command slot */
 1585:     if (mlx_getslot(mc))
 1586: 	goto out;
 1587: 
 1588:     /* build a checkasync command, set the "fix it" flag */
 1589:     mlx_make_type2(mc, MLX_CMD_CHECKASYNC, 0, 0, 0, 0, 0, drive | 0x80, 0, 0);
 1590: 
 1591:     /* start the command and wait for it to be returned */
 1592:     if (mlx_wait_command(mc))
 1593: 	goto out;
 1594:     
 1595:     /* command completed OK? */
 1596:     if (mc->mc_status != 0) {	
 1597: 	device_printf(sc->mlx_dev, "CHECK ASYNC failed - %s\n", mlx_diagnose_command(mc));
 1598:     } else {
 1599: 	device_printf(sc->mlx_sysdrive[drive].ms_disk, "consistency check started");
 1600:     }
 1601:     error = mc->mc_status;
 1602: 
 1603:  out:
 1604:     if (mc != NULL)
 1605: 	mlx_releasecmd(mc);
 1606:     return(error);
 1607: }
 1608: 
 1609: /********************************************************************************
 1610:  * Start a background rebuild of the physical drive at (channel),(target).
 1611:  *
 1612:  * May be called with interrupts enabled or disabled; will return as soon as the
 1613:  * operation has started or been refused.
 1614:  */
 1615: static int
 1616: mlx_rebuild(struct mlx_softc *sc, int channel, int target)
 1617: {
 1618:     struct mlx_command	*mc;
 1619:     int			error;
 1620: 
 1621:     debug_called(1);
 1622: 
 1623:     /* get ourselves a command buffer */
 1624:     error = 0x10000;
 1625:     if ((mc = mlx_alloccmd(sc)) == NULL)
 1626: 	goto out;
 1627:     /* get a command slot */
 1628:     if (mlx_getslot(mc))
 1629: 	goto out;
 1630: 
 1631:     /* build a checkasync command, set the "fix it" flag */
 1632:     mlx_make_type2(mc, MLX_CMD_REBUILDASYNC, channel, target, 0, 0, 0, 0, 0, 0);
 1633: 
 1634:     /* start the command and wait for it to be returned */
 1635:     if (mlx_wait_command(mc))
 1636: 	goto out;
 1637:     
 1638:     /* command completed OK? */
 1639:     if (mc->mc_status != 0) {	
 1640: 	device_printf(sc->mlx_dev, "REBUILD ASYNC failed - %s\n", mlx_diagnose_command(mc));
 1641:     } else {
 1642: 	device_printf(sc->mlx_dev, "drive rebuild started for %d:%d\n", channel, target);
 1643:     }
 1644:     error = mc->mc_status;
 1645: 
 1646:  out:
 1647:     if (mc != NULL)
 1648: 	mlx_releasecmd(mc);
 1649:     return(error);
 1650: }
 1651: 
 1652: /********************************************************************************
 1653:  * Run the command (mc) and return when it completes.
 1654:  *
 1655:  * Interrupts need to be enabled; returns nonzero on error.
 1656:  */
 1657: static int
 1658: mlx_wait_command(struct mlx_command *mc)
 1659: {
 1660:     struct mlx_softc	*sc = mc->mc_sc;
 1661:     int			error, count;
 1662: 
 1663:     debug_called(1);
 1664: 
 1665:     mc->mc_complete = NULL;
 1666:     mc->mc_private = mc;		/* wake us when you're done */
 1667:     if ((error = mlx_start(mc)) != 0)
 1668: 	return(error);
 1669: 
 1670:     count = 0;
 1671:     /* XXX better timeout? */
 1672:     while ((mc->mc_status == MLX_STATUS_BUSY) && (count < 30)) {
 1673: 	tsleep(mc->mc_private, PCATCH, "mlxwcmd", hz);
 1674:     }
 1675: 
 1676:     if (mc->mc_status != 0) {
 1677: 	device_printf(sc->mlx_dev, "command failed - %s\n", mlx_diagnose_command(mc));
 1678: 	return(EIO);
 1679:     }
 1680:     return(0);
 1681: }
 1682: 
 1683: 
 1684: /********************************************************************************
 1685:  * Start the command (mc) and busy-wait for it to complete.
 1686:  *
 1687:  * Should only be used when interrupts can't be relied upon. Returns 0 on 
 1688:  * success, nonzero on error.
 1689:  * Successfully completed commands are dequeued.
 1690:  */
 1691: static int
 1692: mlx_poll_command(struct mlx_command *mc)
 1693: {
 1694:     struct mlx_softc	*sc = mc->mc_sc;
 1695:     int			error, count, s;
 1696: 
 1697:     debug_called(1);
 1698: 
 1699:     mc->mc_complete = NULL;
 1700:     mc->mc_private = NULL;	/* we will poll for it */
 1701:     if ((error = mlx_start(mc)) != 0)
 1702: 	return(error);
 1703:     
 1704:     count = 0;
 1705:     do {
 1706: 	/* poll for completion */
 1707: 	mlx_done(mc->mc_sc);
 1708: 	
 1709:     } while ((mc->mc_status == MLX_STATUS_BUSY) && (count++ < 15000000));
 1710:     if (mc->mc_status != MLX_STATUS_BUSY) {
 1711: 	s = splbio();
 1712: 	TAILQ_REMOVE(&sc->mlx_work, mc, mc_link);
 1713: 	splx(s);
 1714: 	return(0);
 1715:     }
 1716:     device_printf(sc->mlx_dev, "command failed - %s\n", mlx_diagnose_command(mc));
 1717:     return(EIO);
 1718: }
 1719: 
 1720: /********************************************************************************
 1721:  * Pull as much work off the softc's work queue as possible and give it to the
 1722:  * controller.  Leave a couple of slots free for emergencies.
 1723:  *
 1724:  * Must be called at splbio or in an equivalent fashion that prevents 
 1725:  * reentry or activity on the bioq.
 1726:  */
 1727: static void
 1728: mlx_startio(struct mlx_softc *sc)
 1729: {
 1730:     struct mlx_command	*mc;
 1731:     struct mlxd_softc	*mlxd;
 1732:     mlx_bio		*bp;
 1733:     int			blkcount;
 1734:     int			driveno;
 1735:     int			cmd;
 1736:     int			s;
 1737: 
 1738:     /* avoid reentrancy */
 1739:     if (mlx_lock_tas(sc, MLX_LOCK_STARTING))
 1740: 	return;
 1741: 
 1742:     /* spin until something prevents us from doing any work */
 1743:     s = splbio();
 1744:     for (;;) {
 1745: 
 1746: 	/* see if there's work to be done */
 1747: 	if ((bp = MLX_BIO_QFIRST(sc->mlx_bioq)) == NULL)
 1748: 	    break;
 1749: 	/* get a command */
 1750: 	if ((mc = mlx_alloccmd(sc)) == NULL)
 1751: 	    break;
 1752: 	/* get a slot for the command */
 1753: 	if (mlx_getslot(mc) != 0) {
 1754: 	    mlx_releasecmd(mc);
 1755: 	    break;
 1756: 	}
 1757: 	/* get the buf containing our work */
 1758: 	MLX_BIO_QREMOVE(sc->mlx_bioq, bp);
 1759: 	sc->mlx_waitbufs--;
 1760: 	splx(s);
 1761: 	
 1762: 	/* connect the buf to the command */
 1763: 	mc->mc_complete = mlx_completeio;
 1764: 	mc->mc_private = bp;
 1765: 	mc->mc_data = MLX_BIO_DATA(bp);
 1766: 	mc->mc_length = MLX_BIO_LENGTH(bp);
 1767: 	if (MLX_BIO_IS_READ(bp)) {
 1768: 	    mc->mc_flags |= MLX_CMD_DATAIN;
 1769: 	    cmd = MLX_CMD_READSG;
 1770: 	} else {
 1771: 	    mc->mc_flags |= MLX_CMD_DATAOUT;
 1772: 	    cmd = MLX_CMD_WRITESG;
 1773: 	}
 1774: 	
 1775: 	/* map the command so the controller can work with it */
 1776: 	mlx_mapcmd(mc);
 1777: 	
 1778: 	/* build a suitable I/O command (assumes 512-byte rounded transfers) */
 1779: 	mlxd = (struct mlxd_softc *)MLX_BIO_SOFTC(bp);
 1780: 	driveno = mlxd->mlxd_drive - sc->mlx_sysdrive;
 1781: 	blkcount = (MLX_BIO_LENGTH(bp) + MLX_BLKSIZE - 1) / MLX_BLKSIZE;
 1782: 
 1783: 	if ((MLX_BIO_LBA(bp) + blkcount) > sc->mlx_sysdrive[driveno].ms_size)
 1784: 	    device_printf(sc->mlx_dev, "I/O beyond end of unit (%u,%d > %u)\n", 
 1785: 			  MLX_BIO_LBA(bp), blkcount, sc->mlx_sysdrive[driveno].ms_size);
 1786: 
 1787: 	/*
 1788: 	 * Build the I/O command.  Note that the SG list type bits are set to zero,
 1789: 	 * denoting the format of SG list that we are using.
 1790: 	 */
 1791: 	if (sc->mlx_iftype == MLX_IFTYPE_2) {
 1792: 	    mlx_make_type1(mc, (cmd == MLX_CMD_WRITESG) ? MLX_CMD_WRITESG_OLD : MLX_CMD_READSG_OLD,
 1793: 			   blkcount & 0xff, 				/* xfer length low byte */
 1794: 			   MLX_BIO_LBA(bp),				/* physical block number */
 1795: 			   driveno,					/* target drive number */
 1796: 			   mc->mc_sgphys,				/* location of SG list */
 1797: 			   mc->mc_nsgent & 0x3f);			/* size of SG list (top 3 bits clear) */
 1798: 	} else {
 1799: 	    mlx_make_type5(mc, cmd, 
 1800: 			   blkcount & 0xff, 				/* xfer length low byte */
 1801: 			   (driveno << 3) | ((blkcount >> 8) & 0x07),	/* target and length high 3 bits */
 1802: 			   MLX_BIO_LBA(bp),				/* physical block number */
 1803: 			   mc->mc_sgphys,				/* location of SG list */
 1804: 			   mc->mc_nsgent & 0x3f);			/* size of SG list (top 3 bits clear) */
 1805: 	}
 1806: 	
 1807: 	/* try to give command to controller */
 1808: 	if (mlx_start(mc) != 0) {
 1809: 	    /* fail the command */
 1810: 	    mc->mc_status = MLX_STATUS_WEDGED;
 1811: 	    mlx_completeio(mc);
 1812: 	}
 1813: 	s = splbio();
 1814:     }
 1815:     splx(s);
 1816:     mlx_lock_clr(sc, MLX_LOCK_STARTING);
 1817: }
 1818: 
 1819: /********************************************************************************
 1820:  * Handle completion of an I/O command.
 1821:  */
 1822: static void
 1823: mlx_completeio(struct mlx_command *mc)
 1824: {
 1825:     struct mlx_softc	*sc = mc->mc_sc;
 1826:     mlx_bio		*bp = (mlx_bio *)mc->mc_private;
 1827:     struct mlxd_softc	*mlxd = (struct mlxd_softc *)MLX_BIO_SOFTC(bp);
 1828:     
 1829:     if (mc->mc_status != MLX_STATUS_OK) {	/* could be more verbose here? */
 1830: 	MLX_BIO_SET_ERROR(bp, EIO);
 1831: 
 1832: 	switch(mc->mc_status) {
 1833: 	case MLX_STATUS_RDWROFFLINE:		/* system drive has gone offline */
 1834: 	    device_printf(mlxd->mlxd_dev, "drive offline\n");
 1835: 	    /* should signal this with a return code */
 1836: 	    mlxd->mlxd_drive->ms_state = MLX_SYSD_OFFLINE;
 1837: 	    break;
 1838: 
 1839: 	default:				/* other I/O error */
 1840: 	    device_printf(sc->mlx_dev, "I/O error - %s\n", mlx_diagnose_command(mc));
 1841: #if 0
 1842: 	    device_printf(sc->mlx_dev, "  b_bcount %ld  blkcount %ld  b_pblkno %d\n", 
 1843: 			  MLX_BIO_LENGTH(bp), MLX_BIO_LENGTH(bp) / MLX_BLKSIZE, MLX_BIO_LBA(bp));
 1844: 	    device_printf(sc->mlx_dev, "  %13D\n", mc->mc_mailbox, " ");
 1845: #endif
 1846: 	    break;
 1847: 	}
 1848:     }
 1849:     mlx_releasecmd(mc);
 1850:     mlxd_intr(bp);
 1851: }
 1852: 
 1853: /********************************************************************************
 1854:  * Take a command from user-space and try to run it.
 1855:  *
 1856:  * XXX Note that this can't perform very much in the way of error checking, and
 1857:  *     as such, applications _must_ be considered trustworthy.
 1858:  * XXX Commands using S/G for data are not supported.
 1859:  */
 1860: static int
 1861: mlx_user_command(struct mlx_softc *sc, struct mlx_usercommand *mu)
 1862: {
 1863:     struct mlx_command	*mc;
 1864:     struct mlx_dcdb	*dcdb;
 1865:     void		*kbuf;
 1866:     int			error;
 1867:     
 1868:     debug_called(0);
 1869:     
 1870:     kbuf = NULL;
 1871:     mc = NULL;
 1872:     dcdb = NULL;
 1873:     error = ENOMEM;
 1874: 
 1875:     /* get ourselves a command and copy in from user space */
 1876:     if ((mc = mlx_alloccmd(sc)) == NULL)
 1877: 	goto out;
 1878:     bcopy(mu->mu_command, mc->mc_mailbox, sizeof(mc->mc_mailbox));
 1879:     debug(0, "got command buffer");
 1880: 
 1881:     /* if we need a buffer for data transfer, allocate one and copy in its initial contents */
 1882:     if (mu->mu_datasize > 0) {
 1883: 	if (mu->mu_datasize > MAXPHYS)
 1884: 	    return (EINVAL);
 1885: 	if (((kbuf = malloc(mu->mu_datasize, M_DEVBUF, M_WAITOK)) == NULL) ||
 1886: 	    (error = copyin(mu->mu_buf, kbuf, mu->mu_datasize)))
 1887: 	    goto out;
 1888: 	debug(0, "got kernel buffer");
 1889:     }
 1890: 
 1891:     /* get a command slot */
 1892:     if (mlx_getslot(mc))
 1893: 	goto out;
 1894:     debug(0, "got a slot");
 1895:     
 1896:     /* map the command so the controller can see it */
 1897:     mc->mc_data = kbuf;
 1898:     mc->mc_length = mu->mu_datasize;
 1899:     mlx_mapcmd(mc);
 1900:     debug(0, "mapped");
 1901: 
 1902:     /* 
 1903:      * If this is a passthrough SCSI command, the DCDB is packed at the 
 1904:      * beginning of the data area.  Fix up the DCDB to point to the correct physical
 1905:      * address and override any bufptr supplied by the caller since we know
 1906:      * what it's meant to be.
 1907:      */
 1908:     if (mc->mc_mailbox[0] == MLX_CMD_DIRECT_CDB) {
 1909: 	dcdb = (struct mlx_dcdb *)kbuf;
 1910: 	dcdb->dcdb_physaddr = mc->mc_dataphys + sizeof(*dcdb);
 1911: 	mu->mu_bufptr = 8;
 1912:     }
 1913:     
 1914:     /* 
 1915:      * If there's a data buffer, fix up the command's buffer pointer.
 1916:      */
 1917:     if (mu->mu_datasize > 0) {
 1918: 
 1919: 	/* range check the pointer to physical buffer address */
 1920: 	if ((mu->mu_bufptr < 0) || (mu->mu_bufptr > (sizeof(mu->mu_command) - sizeof(u_int32_t)))) {
 1921: 	    error = EINVAL;
 1922: 	    goto out;
 1923: 	}
 1924: 	mc->mc_mailbox[mu->mu_bufptr    ] =  mc->mc_dataphys        & 0xff;
 1925: 	mc->mc_mailbox[mu->mu_bufptr + 1] = (mc->mc_dataphys >> 8)  & 0xff;
 1926: 	mc->mc_mailbox[mu->mu_bufptr + 2] = (mc->mc_dataphys >> 16) & 0xff;
 1927: 	mc->mc_mailbox[mu->mu_bufptr + 3] = (mc->mc_dataphys >> 24) & 0xff;
 1928:     }
 1929:     debug(0, "command fixup");
 1930: 
 1931:     /* submit the command and wait */
 1932:     if ((error = mlx_wait_command(mc)) != 0)
 1933: 	goto out;
 1934: 
 1935:     /* copy out status and data */
 1936:     mu->mu_status = mc->mc_status;
 1937:     if ((mu->mu_datasize > 0) && ((error = copyout(kbuf, mu->mu_buf, mu->mu_datasize))))
 1938: 	goto out;
 1939:     error = 0;
 1940:     
 1941:  out:
 1942:     mlx_releasecmd(mc);
 1943:     if (kbuf != NULL)
 1944: 	free(kbuf, M_DEVBUF);
 1945:     return(error);
 1946: }
 1947: 
 1948: /********************************************************************************
 1949:  ********************************************************************************
 1950:                                                         Command I/O to Controller
 1951:  ********************************************************************************
 1952:  ********************************************************************************/
 1953: 
 1954: /********************************************************************************
 1955:  * Find a free command slot for (mc).
 1956:  *
 1957:  * Don't hand out a slot to a normal-priority command unless there are at least
 1958:  * 4 slots free for priority commands.
 1959:  */
 1960: static int
 1961: mlx_getslot(struct mlx_command *mc)
 1962: {
 1963:     struct mlx_softc	*sc = mc->mc_sc;
 1964:     int			s, slot, limit;
 1965: 
 1966:     debug_called(1);
 1967: 
 1968:     /* 
 1969:      * Enforce slot-usage limit, if we have the required information.
 1970:      */
 1971:     if (sc->mlx_enq2 != NULL) {
 1972: 	limit = sc->mlx_enq2->me_max_commands;
 1973:     } else {
 1974: 	limit = 2;
 1975:     }
 1976:     if (sc->mlx_busycmds >= ((mc->mc_flags & MLX_CMD_PRIORITY) ? limit : limit - 4))
 1977: 	return(EBUSY);
 1978: 
 1979:     /* 
 1980:      * Allocate an outstanding command slot 
 1981:      *
 1982:      * XXX linear search is slow
 1983:      */
 1984:     s = splbio();
 1985:     for (slot = 0; slot < limit; slot++) {
 1986: 	debug(2, "try slot %d", slot);
 1987: 	if (sc->mlx_busycmd[slot] == NULL)
 1988: 	    break;
 1989:     }
 1990:     if (slot < limit) {
 1991: 	sc->mlx_busycmd[slot] = mc;
 1992: 	sc->mlx_busycmds++;
 1993:     }
 1994:     splx(s);
 1995: 
 1996:     /* out of slots? */
 1997:     if (slot >= limit)
 1998: 	return(EBUSY);
 1999: 
 2000:     debug(2, "got slot %d", slot);
 2001:     mc->mc_slot = slot;
 2002:     return(0);
 2003: }
 2004: 
 2005: /********************************************************************************
 2006:  * Map/unmap (mc)'s data in the controller's addressable space.
 2007:  */
 2008: static void
 2009: mlx_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
 2010: {
 2011:     struct mlx_command	*mc = (struct mlx_command *)arg;
 2012:     struct mlx_softc	*sc = mc->mc_sc;
 2013:     struct mlx_sgentry	*sg;
 2014:     int			i;
 2015: 
 2016:     debug_called(1);
 2017: 
 2018:     /* XXX should be unnecessary */
 2019:     if (sc->mlx_enq2 && (nsegments > sc->mlx_enq2->me_max_sg))
 2020: 	panic("MLX: too many s/g segments (%d, max %d)", nsegments, sc->mlx_enq2->me_max_sg);
 2021: 
 2022:     /* get base address of s/g table */
 2023:     sg = sc->mlx_sgtable + (mc->mc_slot * MLX_NSEG);
 2024: 
 2025:     /* save s/g table information in command */
 2026:     mc->mc_nsgent = nsegments;
 2027:     mc->mc_sgphys = sc->mlx_sgbusaddr + (mc->mc_slot * MLX_NSEG * sizeof(struct mlx_sgentry));
 2028:     mc->mc_dataphys = segs[0].ds_addr;
 2029: 
 2030:     /* populate s/g table */
 2031:     for (i = 0; i < nsegments; i++, sg++) {
 2032: 	sg->sg_addr = segs[i].ds_addr;
 2033: 	sg->sg_count = segs[i].ds_len;
 2034:     }
 2035: }
 2036: 
 2037: static void
 2038: mlx_mapcmd(struct mlx_command *mc)
 2039: {
 2040:     struct mlx_softc	*sc = mc->mc_sc;
 2041: 
 2042:     debug_called(1);
 2043: 
 2044:     /* if the command involves data at all */
 2045:     if (mc->mc_data != NULL) {
 2046: 	
 2047: 	/* map the data buffer into bus space and build the s/g list */
 2048: 	bus_dmamap_load(sc->mlx_buffer_dmat, mc->mc_dmamap, mc->mc_data, mc->mc_length, 
 2049: 			mlx_setup_dmamap, mc, 0);
 2050: 	if (mc->mc_flags & MLX_CMD_DATAIN)
 2051: 	    bus_dmamap_sync(sc->mlx_buffer_dmat, mc->mc_dmamap, BUS_DMASYNC_PREREAD);
 2052: 	if (mc->mc_flags & MLX_CMD_DATAOUT)
 2053: 	    bus_dmamap_sync(sc->mlx_buffer_dmat, mc->mc_dmamap, BUS_DMASYNC_PREWRITE);
 2054:     }
 2055: }
 2056: 
 2057: static void
 2058: mlx_unmapcmd(struct mlx_command *mc)
 2059: {
 2060:     struct mlx_softc	*sc = mc->mc_sc;
 2061: 
 2062:     debug_called(1);
 2063: 
 2064:     /* if the command involved data at all */
 2065:     if (mc->mc_data != NULL) {
 2066: 	
 2067: 	if (mc->mc_flags & MLX_CMD_DATAIN)
 2068: 	    bus_dmamap_sync(sc->mlx_buffer_dmat, mc->mc_dmamap, BUS_DMASYNC_POSTREAD);
 2069: 	if (mc->mc_flags & MLX_CMD_DATAOUT)
 2070: 	    bus_dmamap_sync(sc->mlx_buffer_dmat, mc->mc_dmamap, BUS_DMASYNC_POSTWRITE);
 2071: 
 2072: 	bus_dmamap_unload(sc->mlx_buffer_dmat, mc->mc_dmamap); 
 2073:     }
 2074: }
 2075: 
 2076: /********************************************************************************
 2077:  * Try to deliver (mc) to the controller.
 2078:  *
 2079:  * Can be called at any interrupt level, with or without interrupts enabled.
 2080:  */
 2081: static int
 2082: mlx_start(struct mlx_command *mc)
 2083: {
 2084:     struct mlx_softc	*sc = mc->mc_sc;
 2085:     int			i, s, done;
 2086: 
 2087:     debug_called(1);
 2088: 
 2089:     /* save the slot number as ident so we can handle this command when complete */
 2090:     mc->mc_mailbox[0x1] = mc->mc_slot;
 2091: 
 2092:     /* mark the command as currently being processed */
 2093:     mc->mc_status = MLX_STATUS_BUSY;
 2094: 
 2095:     /* set a default 60-second timeout  XXX tunable?  XXX not currently used */
 2096:     mc->mc_timeout = time_second + 60;
 2097:     
 2098:     /* spin waiting for the mailbox */
 2099:     for (i = 100000, done = 0; (i > 0) && !done; i--) {
 2100: 	s = splbio();
 2101: 	if (sc->mlx_tryqueue(sc, mc)) {
 2102: 	    done = 1;
 2103: 	    /* move command to work queue */
 2104: 	    TAILQ_INSERT_TAIL(&sc->mlx_work, mc, mc_link);
 2105: 	}
 2106: 	splx(s);	/* drop spl to allow completion interrupts */
 2107:     }
 2108: 
 2109:     /* command is enqueued */
 2110:     if (done)
 2111: 	return(0);
 2112: 
 2113:     /* 
 2114:      * We couldn't get the controller to take the command.  Revoke the slot
 2115:      * that the command was given and return it with a bad status.
 2116:      */
 2117:     sc->mlx_busycmd[mc->mc_slot] = NULL;
 2118:     device_printf(sc->mlx_dev, "controller wedged (not taking commands)\n");
 2119:     mc->mc_status = MLX_STATUS_WEDGED;
 2120:     mlx_complete(sc);
 2121:     return(EIO);
 2122: }
 2123: 
 2124: /********************************************************************************
 2125:  * Poll the controller (sc) for completed commands.
 2126:  * Update command status and free slots for reuse.  If any slots were freed,
 2127:  * new commands may be posted.
 2128:  *
 2129:  * Returns nonzero if one or more commands were completed.
 2130:  */
 2131: static int
 2132: mlx_done(struct mlx_softc *sc)
 2133: {
 2134:     struct mlx_command	*mc;
 2135:     int			s, result;
 2136:     u_int8_t		slot;
 2137:     u_int16_t		status;
 2138:     
 2139:     debug_called(2);
 2140: 
 2141:     result = 0;
 2142: 
 2143:     /* loop collecting completed commands */
 2144:     s = splbio();
 2145:     for (;;) {
 2146: 	/* poll for a completed command's identifier and status */
 2147: 	if (sc->mlx_findcomplete(sc, &slot, &status)) {
 2148: 	    result = 1;
 2149: 	    mc = sc->mlx_busycmd[slot];			/* find command */
 2150: 	    if (mc != NULL) {				/* paranoia */
 2151: 		if (mc->mc_status == MLX_STATUS_BUSY) {
 2152: 		    mc->mc_status = status;		/* save status */
 2153: 
 2154: 		    /* free slot for reuse */
 2155: 		    sc->mlx_busycmd[slot] = NULL;
 2156: 		    sc->mlx_busycmds--;
 2157: 		} else {
 2158: 		    device_printf(sc->mlx_dev, "duplicate done event for slot %d\n", slot);
 2159: 		}
 2160: 	    } else {
 2161: 		device_printf(sc->mlx_dev, "done event for nonbusy slot %d\n", slot);
 2162: 	    }
 2163: 	} else {
 2164: 	    break;
 2165: 	}
 2166:     }
 2167:     splx(s);
 2168: 
 2169:     /* if we've completed any commands, try posting some more */
 2170:     if (result)
 2171: 	mlx_startio(sc);
 2172: 
 2173:     /* handle completion and timeouts */
 2174:     mlx_complete(sc);
 2175: 
 2176:     return(result);
 2177: }
 2178: 
 2179: /********************************************************************************
 2180:  * Perform post-completion processing for commands on (sc).
 2181:  */
 2182: static void
 2183: mlx_complete(struct mlx_softc *sc) 
 2184: {
 2185:     struct mlx_command	*mc, *nc;
 2186:     int			s, count;
 2187:     
 2188:     debug_called(2);
 2189: 
 2190:     /* avoid reentrancy  XXX might want to signal and request a restart */
 2191:     if (mlx_lock_tas(sc, MLX_LOCK_COMPLETING))
 2192: 	return;
 2193: 
 2194:     s = splbio();
 2195:     count = 0;
 2196: 
 2197:     /* scan the list of busy/done commands */
 2198:     mc = TAILQ_FIRST(&sc->mlx_work);
 2199:     while (mc != NULL) {
 2200: 	nc = TAILQ_NEXT(mc, mc_link);
 2201: 
 2202: 	/* Command has been completed in some fashion */
 2203: 	if (mc->mc_status != MLX_STATUS_BUSY) {
 2204: 	
 2205: 	    /* unmap the command's data buffer */
 2206: 	    mlx_unmapcmd(mc);
 2207: 	    /*
 2208: 	     * Does the command have a completion handler?
 2209: 	     */
 2210: 	    if (mc->mc_complete != NULL) {
 2211: 		/* remove from list and give to handler */
 2212: 		TAILQ_REMOVE(&sc->mlx_work, mc, mc_link);
 2213: 		mc->mc_complete(mc);
 2214: 
 2215: 		/* 
 2216: 		 * Is there a sleeper waiting on this command?
 2217: 		 */
 2218: 	    } else if (mc->mc_private != NULL) {	/* sleeping caller wants to know about it */
 2219: 
 2220: 		/* remove from list and wake up sleeper */
 2221: 		TAILQ_REMOVE(&sc->mlx_work, mc, mc_link);
 2222: 		wakeup_one(mc->mc_private);
 2223: 
 2224: 		/*
 2225: 		 * Leave the command for a caller that's polling for it.
 2226: 		 */
 2227: 	    } else {
 2228: 	    }
 2229: 	}
 2230: 	mc = nc;
 2231:     }
 2232:     splx(s);
 2233: 
 2234:     mlx_lock_clr(sc, MLX_LOCK_COMPLETING);
 2235: }
 2236: 
 2237: /********************************************************************************
 2238:  ********************************************************************************
 2239:                                                         Command Buffer Management
 2240:  ********************************************************************************
 2241:  ********************************************************************************/
 2242: 
 2243: /********************************************************************************
 2244:  * Get a new command buffer.
 2245:  *
 2246:  * This may return NULL in low-memory cases.
 2247:  *
 2248:  * Note that using malloc() is expensive (the command buffer is << 1 page) but
 2249:  * necessary if we are to be a loadable module before the zone allocator is fixed.
 2250:  *
 2251:  * If possible, we recycle a command buffer that's been used before.
 2252:  *
 2253:  * XXX Note that command buffers are not cleaned out - it is the caller's 
 2254:  *     responsibility to ensure that all required fields are filled in before
 2255:  *     using a buffer.
 2256:  */
 2257: static struct mlx_command *
 2258: mlx_alloccmd(struct mlx_softc *sc)
 2259: {
 2260:     struct mlx_command	*mc;
 2261:     int			error;
 2262:     int			s;
 2263: 
 2264:     debug_called(1);
 2265: 
 2266:     s = splbio();
 2267:     if ((mc = TAILQ_FIRST(&sc->mlx_freecmds)) != NULL)
 2268: 	TAILQ_REMOVE(&sc->mlx_freecmds, mc, mc_link);
 2269:     splx(s);
 2270: 
 2271:     /* allocate a new command buffer? */
 2272:     if (mc == NULL) {
 2273: 	mc = (struct mlx_command *)malloc(sizeof(*mc), M_DEVBUF, M_NOWAIT | M_ZERO);
 2274: 	if (mc != NULL) {
 2275: 	    mc->mc_sc = sc;
 2276: 	    error = bus_dmamap_create(sc->mlx_buffer_dmat, 0, &mc->mc_dmamap);
 2277: 	    if (error) {
 2278: 		free(mc, M_DEVBUF);
 2279: 		return(NULL);
 2280: 	    }
 2281: 	}
 2282:     }
 2283:     return(mc);
 2284: }
 2285: 
 2286: /********************************************************************************
 2287:  * Release a command buffer for recycling.
 2288:  *
 2289:  * XXX It might be a good idea to limit the number of commands we save for reuse
 2290:  *     if it's shown that this list bloats out massively.
 2291:  */
 2292: static void
 2293: mlx_releasecmd(struct mlx_command *mc)
 2294: {
 2295:     int		s;
 2296:     
 2297:     debug_called(1);
 2298: 
 2299:     s = splbio();
 2300:     TAILQ_INSERT_HEAD(&mc->mc_sc->mlx_freecmds, mc, mc_link);
 2301:     splx(s);
 2302: }
 2303: 
 2304: /********************************************************************************
 2305:  * Permanently discard a command buffer.
 2306:  */
 2307: static void
 2308: mlx_freecmd(struct mlx_command *mc) 
 2309: {
 2310:     struct mlx_softc	*sc = mc->mc_sc;
 2311:     
 2312:     debug_called(1);
 2313:     bus_dmamap_destroy(sc->mlx_buffer_dmat, mc->mc_dmamap);
 2314:     free(mc, M_DEVBUF);
 2315: }
 2316: 
 2317: 
 2318: /********************************************************************************
 2319:  ********************************************************************************
 2320:                                                 Type 3 interface accessor methods
 2321:  ********************************************************************************
 2322:  ********************************************************************************/
 2323: 
 2324: /********************************************************************************
 2325:  * Try to give (mc) to the controller.  Returns 1 if successful, 0 on failure
 2326:  * (the controller is not ready to take a command).
 2327:  *
 2328:  * Must be called at splbio or in a fashion that prevents reentry.
 2329:  */
 2330: static int
 2331: mlx_v3_tryqueue(struct mlx_softc *sc, struct mlx_command *mc)
 2332: {
 2333:     int		i;
 2334:     
 2335:     debug_called(2);
 2336: 
 2337:     /* ready for our command? */
 2338:     if (!(MLX_V3_GET_IDBR(sc) & MLX_V3_IDB_FULL)) {
 2339: 	/* copy mailbox data to window */
 2340: 	for (i = 0; i < 13; i++)
 2341: 	    MLX_V3_PUT_MAILBOX(sc, i, mc->mc_mailbox[i]);
 2342: 	
 2343: 	/* post command */
 2344: 	MLX_V3_PUT_IDBR(sc, MLX_V3_IDB_FULL);
 2345: 	return(1);
 2346:     }
 2347:     return(0);
 2348: }
 2349: 
 2350: /********************************************************************************
 2351:  * See if a command has been completed, if so acknowledge its completion
 2352:  * and recover the slot number and status code.
 2353:  *
 2354:  * Must be called at splbio or in a fashion that prevents reentry.
 2355:  */
 2356: static int
 2357: mlx_v3_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status)
 2358: {
 2359: 
 2360:     debug_called(2);
 2361: 
 2362:     /* status available? */
 2363:     if (MLX_V3_GET_ODBR(sc) & MLX_V3_ODB_SAVAIL) {
 2364: 	*slot = MLX_V3_GET_STATUS_IDENT(sc);		/* get command identifier */
 2365: 	*status = MLX_V3_GET_STATUS(sc);		/* get status */
 2366: 
 2367: 	/* acknowledge completion */
 2368: 	MLX_V3_PUT_ODBR(sc, MLX_V3_ODB_SAVAIL);
 2369: 	MLX_V3_PUT_IDBR(sc, MLX_V3_IDB_SACK);
 2370: 	return(1);
 2371:     }
 2372:     return(0);
 2373: }
 2374: 
 2375: /********************************************************************************
 2376:  * Enable/disable interrupts as requested. (No acknowledge required)
 2377:  *
 2378:  * Must be called at splbio or in a fashion that prevents reentry.
 2379:  */
 2380: static void
 2381: mlx_v3_intaction(struct mlx_softc *sc, int action)
 2382: {
 2383:     debug_called(1);
 2384: 
 2385:     switch(action) {
 2386:     case MLX_INTACTION_DISABLE:
 2387: 	MLX_V3_PUT_IER(sc, 0);
 2388: 	sc->mlx_state &= ~MLX_STATE_INTEN;
 2389: 	break;
 2390:     case MLX_INTACTION_ENABLE:
 2391: 	MLX_V3_PUT_IER(sc, 1);
 2392: 	sc->mlx_state |= MLX_STATE_INTEN;
 2393: 	break;
 2394:     }
 2395: }
 2396: 
 2397: /********************************************************************************
 2398:  * Poll for firmware error codes during controller initialisation.
 2399:  * Returns 0 if initialisation is complete, 1 if still in progress but no 
 2400:  * error has been fetched, 2 if an error has been retrieved.
 2401:  */
 2402: static int 
 2403: mlx_v3_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2)
 2404: {
 2405:     u_int8_t	fwerror;
 2406:     static int	initted = 0;
 2407: 
 2408:     debug_called(2);
 2409: 
 2410:     /* first time around, clear any hardware completion status */
 2411:     if (!initted) {
 2412: 	MLX_V3_PUT_IDBR(sc, MLX_V3_IDB_SACK);
 2413: 	DELAY(1000);
 2414: 	initted = 1;
 2415:     }
 2416: 
 2417:     /* init in progress? */
 2418:     if (!(MLX_V3_GET_IDBR(sc) & MLX_V3_IDB_INIT_BUSY))
 2419: 	return(0);
 2420: 
 2421:     /* test error value */
 2422:     fwerror = MLX_V3_GET_FWERROR(sc);
 2423:     if (!(fwerror & MLX_V3_FWERROR_PEND))
 2424: 	return(1);
 2425: 
 2426:     /* mask status pending bit, fetch status */
 2427:     *error = fwerror & ~MLX_V3_FWERROR_PEND;
 2428:     *param1 = MLX_V3_GET_FWERROR_PARAM1(sc);
 2429:     *param2 = MLX_V3_GET_FWERROR_PARAM2(sc);
 2430: 
 2431:     /* acknowledge */
 2432:     MLX_V3_PUT_FWERROR(sc, 0);
 2433: 
 2434:     return(2);
 2435: }
 2436: 
 2437: /********************************************************************************
 2438:  ********************************************************************************
 2439:                                                 Type 4 interface accessor methods
 2440:  ********************************************************************************
 2441:  ********************************************************************************/
 2442: 
 2443: /********************************************************************************
 2444:  * Try to give (mc) to the controller.  Returns 1 if successful, 0 on failure
 2445:  * (the controller is not ready to take a command).
 2446:  *
 2447:  * Must be called at splbio or in a fashion that prevents reentry.
 2448:  */
 2449: static int
 2450: mlx_v4_tryqueue(struct mlx_softc *sc, struct mlx_command *mc)
 2451: {
 2452:     int		i;
 2453:     
 2454:     debug_called(2);
 2455: 
 2456:     /* ready for our command? */
 2457:     if (!(MLX_V4_GET_IDBR(sc) & MLX_V4_IDB_FULL)) {
 2458: 	/* copy mailbox data to window */
 2459: 	for (i = 0; i < 13; i++)
 2460: 	    MLX_V4_PUT_MAILBOX(sc, i, mc->mc_mailbox[i]);
 2461: 	
 2462: 	/* memory-mapped controller, so issue a write barrier to ensure the mailbox is filled */
 2463: 	bus_space_barrier(sc->mlx_btag, sc->mlx_bhandle, MLX_V4_MAILBOX, MLX_V4_MAILBOX_LENGTH,
 2464: 			  BUS_SPACE_BARRIER_WRITE);
 2465: 
 2466: 	/* post command */
 2467: 	MLX_V4_PUT_IDBR(sc, MLX_V4_IDB_HWMBOX_CMD);
 2468: 	return(1);
 2469:     }
 2470:     return(0);
 2471: }
 2472: 
 2473: /********************************************************************************
 2474:  * See if a command has been completed, if so acknowledge its completion
 2475:  * and recover the slot number and status code.
 2476:  *
 2477:  * Must be called at splbio or in a fashion that prevents reentry.
 2478:  */
 2479: static int
 2480: mlx_v4_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status)
 2481: {
 2482: 
 2483:     debug_called(2);
 2484: 
 2485:     /* status available? */
 2486:     if (MLX_V4_GET_ODBR(sc) & MLX_V4_ODB_HWSAVAIL) {
 2487: 	*slot = MLX_V4_GET_STATUS_IDENT(sc);		/* get command identifier */
 2488: 	*status = MLX_V4_GET_STATUS(sc);		/* get status */
 2489: 
 2490: 	/* acknowledge completion */
 2491: 	MLX_V4_PUT_ODBR(sc, MLX_V4_ODB_HWMBOX_ACK);
 2492: 	MLX_V4_PUT_IDBR(sc, MLX_V4_IDB_SACK);
 2493: 	return(1);
 2494:     }
 2495:     return(0);
 2496: }
 2497: 
 2498: /********************************************************************************
 2499:  * Enable/disable interrupts as requested.
 2500:  *
 2501:  * Must be called at splbio or in a fashion that prevents reentry.
 2502:  */
 2503: static void
 2504: mlx_v4_intaction(struct mlx_softc *sc, int action)
 2505: {
 2506:     debug_called(1);
 2507: 
 2508:     switch(action) {
 2509:     case MLX_INTACTION_DISABLE:
 2510: 	MLX_V4_PUT_IER(sc, MLX_V4_IER_MASK | MLX_V4_IER_DISINT);
 2511: 	sc->mlx_state &= ~MLX_STATE_INTEN;
 2512: 	break;
 2513:     case MLX_INTACTION_ENABLE:
 2514: 	MLX_V4_PUT_IER(sc, MLX_V4_IER_MASK & ~MLX_V4_IER_DISINT);
 2515: 	sc->mlx_state |= MLX_STATE_INTEN;
 2516: 	break;
 2517:     }
 2518: }
 2519: 
 2520: /********************************************************************************
 2521:  * Poll for firmware error codes during controller initialisation.
 2522:  * Returns 0 if initialisation is complete, 1 if still in progress but no 
 2523:  * error has been fetched, 2 if an error has been retrieved.
 2524:  */
 2525: static int 
 2526: mlx_v4_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2)
 2527: {
 2528:     u_int8_t	fwerror;
 2529:     static int	initted = 0;
 2530: 
 2531:     debug_called(2);
 2532: 
 2533:     /* first time around, clear any hardware completion status */
 2534:     if (!initted) {
 2535: 	MLX_V4_PUT_IDBR(sc, MLX_V4_IDB_SACK);
 2536: 	DELAY(1000);
 2537: 	initted = 1;
 2538:     }
 2539: 
 2540:     /* init in progress? */
 2541:     if (!(MLX_V4_GET_IDBR(sc) & MLX_V4_IDB_INIT_BUSY))
 2542: 	return(0);
 2543: 
 2544:     /* test error value */
 2545:     fwerror = MLX_V4_GET_FWERROR(sc);
 2546:     if (!(fwerror & MLX_V4_FWERROR_PEND))
 2547: 	return(1);
 2548: 
 2549:     /* mask status pending bit, fetch status */
 2550:     *error = fwerror & ~MLX_V4_FWERROR_PEND;
 2551:     *param1 = MLX_V4_GET_FWERROR_PARAM1(sc);
 2552:     *param2 = MLX_V4_GET_FWERROR_PARAM2(sc);
 2553: 
 2554:     /* acknowledge */
 2555:     MLX_V4_PUT_FWERROR(sc, 0);
 2556: 
 2557:     return(2);
 2558: }
 2559: 
 2560: /********************************************************************************
 2561:  ********************************************************************************
 2562:                                                 Type 5 interface accessor methods
 2563:  ********************************************************************************
 2564:  ********************************************************************************/
 2565: 
 2566: /********************************************************************************
 2567:  * Try to give (mc) to the controller.  Returns 1 if successful, 0 on failure
 2568:  * (the controller is not ready to take a command).
 2569:  *
 2570:  * Must be called at splbio or in a fashion that prevents reentry.
 2571:  */
 2572: static int
 2573: mlx_v5_tryqueue(struct mlx_softc *sc, struct mlx_command *mc)
 2574: {
 2575:     int		i;
 2576: 
 2577:     debug_called(2);
 2578: 
 2579:     /* ready for our command? */
 2580:     if (MLX_V5_GET_IDBR(sc) & MLX_V5_IDB_EMPTY) {
 2581: 	/* copy mailbox data to window */
 2582: 	for (i = 0; i < 13; i++)
 2583: 	    MLX_V5_PUT_MAILBOX(sc, i, mc->mc_mailbox[i]);
 2584: 
 2585: 	/* post command */
 2586: 	MLX_V5_PUT_IDBR(sc, MLX_V5_IDB_HWMBOX_CMD);
 2587: 	return(1);
 2588:     }
 2589:     return(0);
 2590: }
 2591: 
 2592: /********************************************************************************
 2593:  * See if a command has been completed, if so acknowledge its completion
 2594:  * and recover the slot number and status code.
 2595:  *
 2596:  * Must be called at splbio or in a fashion that prevents reentry.
 2597:  */
 2598: static int
 2599: mlx_v5_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status)
 2600: {
 2601: 
 2602:     debug_called(2);
 2603: 
 2604:     /* status available? */
 2605:     if (MLX_V5_GET_ODBR(sc) & MLX_V5_ODB_HWSAVAIL) {
 2606: 	*slot = MLX_V5_GET_STATUS_IDENT(sc);		/* get command identifier */
 2607: 	*status = MLX_V5_GET_STATUS(sc);		/* get status */
 2608: 
 2609: 	/* acknowledge completion */
 2610: 	MLX_V5_PUT_ODBR(sc, MLX_V5_ODB_HWMBOX_ACK);
 2611: 	MLX_V5_PUT_IDBR(sc, MLX_V5_IDB_SACK);
 2612: 	return(1);
 2613:     }
 2614:     return(0);
 2615: }
 2616: 
 2617: /********************************************************************************
 2618:  * Enable/disable interrupts as requested.
 2619:  *
 2620:  * Must be called at splbio or in a fashion that prevents reentry.
 2621:  */
 2622: static void
 2623: mlx_v5_intaction(struct mlx_softc *sc, int action)
 2624: {
 2625:     debug_called(1);
 2626: 
 2627:     switch(action) {
 2628:     case MLX_INTACTION_DISABLE:
 2629: 	MLX_V5_PUT_IER(sc, 0xff & MLX_V5_IER_DISINT);
 2630: 	sc->mlx_state &= ~MLX_STATE_INTEN;
 2631: 	break;
 2632:     case MLX_INTACTION_ENABLE:
 2633: 	MLX_V5_PUT_IER(sc, 0xff & ~MLX_V5_IER_DISINT);
 2634: 	sc->mlx_state |= MLX_STATE_INTEN;
 2635: 	break;
 2636:     }
 2637: }
 2638: 
 2639: /********************************************************************************
 2640:  * Poll for firmware error codes during controller initialisation.
 2641:  * Returns 0 if initialisation is complete, 1 if still in progress but no 
 2642:  * error has been fetched, 2 if an error has been retrieved.
 2643:  */
 2644: static int 
 2645: mlx_v5_fw_handshake(struct mlx_softc *sc, int *error, int *param1, int *param2)
 2646: {
 2647:     u_int8_t	fwerror;
 2648:     static int	initted = 0;
 2649: 
 2650:     debug_called(2);
 2651: 
 2652:     /* first time around, clear any hardware completion status */
 2653:     if (!initted) {
 2654: 	MLX_V5_PUT_IDBR(sc, MLX_V5_IDB_SACK);
 2655: 	DELAY(1000);
 2656: 	initted = 1;
 2657:     }
 2658: 
 2659:     /* init in progress? */
 2660:     if (MLX_V5_GET_IDBR(sc) & MLX_V5_IDB_INIT_DONE)
 2661: 	return(0);
 2662: 
 2663:     /* test for error value */
 2664:     fwerror = MLX_V5_GET_FWERROR(sc);
 2665:     if (!(fwerror & MLX_V5_FWERROR_PEND))
 2666: 	return(1);
 2667: 
 2668:     /* mask status pending bit, fetch status */
 2669:     *error = fwerror & ~MLX_V5_FWERROR_PEND;
 2670:     *param1 = MLX_V5_GET_FWERROR_PARAM1(sc);
 2671:     *param2 = MLX_V5_GET_FWERROR_PARAM2(sc);
 2672: 
 2673:     /* acknowledge */
 2674:     MLX_V5_PUT_FWERROR(sc, 0xff);
 2675: 
 2676:     return(2);
 2677: }
 2678: 
 2679: /********************************************************************************
 2680:  ********************************************************************************
 2681:                                                                         Debugging
 2682:  ********************************************************************************
 2683:  ********************************************************************************/
 2684: 
 2685: /********************************************************************************
 2686:  * Return a status message describing (mc)
 2687:  */
 2688: static char *mlx_status_messages[] = {
 2689:     "normal completion",			/* 00 */
 2690:     "irrecoverable data error",			/* 01 */
 2691:     "drive does not exist, or is offline",	/* 02 */
 2692:     "attempt to write beyond end of drive",	/* 03 */
 2693:     "bad data encountered",			/* 04 */
 2694:     "invalid log entry request",		/* 05 */
 2695:     "attempt to rebuild online drive",		/* 06 */
 2696:     "new disk failed during rebuild",		/* 07 */
 2697:     "invalid channel/target",			/* 08 */
 2698:     "rebuild/check already in progress",	/* 09 */
 2699:     "one or more disks are dead",		/* 10 */
 2700:     "invalid or non-redundant drive",		/* 11 */
 2701:     "channel is busy",				/* 12 */
 2702:     "channel is not stopped",			/* 13 */
 2703:     "rebuild successfully terminated",		/* 14 */
 2704:     "unsupported command",			/* 15 */
 2705:     "check condition received",			/* 16 */
 2706:     "device is busy",				/* 17 */
 2707:     "selection or command timeout",		/* 18 */
 2708:     "command terminated abnormally",		/* 19 */
 2709:     ""
 2710: };
 2711: 
 2712: static struct
 2713: {
 2714:     int		command;
 2715:     u_int16_t	status;
 2716:     int		msg;
 2717: } mlx_messages[] = {
 2718:     {MLX_CMD_READSG,		0x0001,	 1},
 2719:     {MLX_CMD_READSG,		0x0002,	 1},
 2720:     {MLX_CMD_READSG,		0x0105,	 3},
 2721:     {MLX_CMD_READSG,		0x010c,	 4},
 2722:     {MLX_CMD_WRITESG,		0x0001,	 1},
 2723:     {MLX_CMD_WRITESG,		0x0002,	 1},
 2724:     {MLX_CMD_WRITESG,		0x0105,	 3},
 2725:     {MLX_CMD_READSG_OLD,	0x0001,	 1},
 2726:     {MLX_CMD_READSG_OLD,	0x0002,	 1},
 2727:     {MLX_CMD_READSG_OLD,	0x0105,	 3},
 2728:     {MLX_CMD_WRITESG_OLD,	0x0001,	 1},
 2729:     {MLX_CMD_WRITESG_OLD,	0x0002,	 1},
 2730:     {MLX_CMD_WRITESG_OLD,	0x0105,	 3},
 2731:     {MLX_CMD_LOGOP,		0x0105,	 5},
 2732:     {MLX_CMD_REBUILDASYNC,	0x0002,  6},
 2733:     {MLX_CMD_REBUILDASYNC,	0x0004,  7},
 2734:     {MLX_CMD_REBUILDASYNC,	0x0105,  8},
 2735:     {MLX_CMD_REBUILDASYNC,	0x0106,  9},
 2736:     {MLX_CMD_REBUILDASYNC,	0x0107, 14},
 2737:     {MLX_CMD_CHECKASYNC,	0x0002, 10},
 2738:     {MLX_CMD_CHECKASYNC,	0x0105, 11},
 2739:     {MLX_CMD_CHECKASYNC,	0x0106,  9},
 2740:     {MLX_CMD_STOPCHANNEL,	0x0106, 12},
 2741:     {MLX_CMD_STOPCHANNEL,	0x0105,  8},
 2742:     {MLX_CMD_STARTCHANNEL,	0x0005, 13},
 2743:     {MLX_CMD_STARTCHANNEL,	0x0105,  8},
 2744:     {MLX_CMD_DIRECT_CDB,	0x0002, 16},
 2745:     {MLX_CMD_DIRECT_CDB,	0x0008, 17},
 2746:     {MLX_CMD_DIRECT_CDB,	0x000e, 18},
 2747:     {MLX_CMD_DIRECT_CDB,	0x000f, 19},
 2748:     {MLX_CMD_DIRECT_CDB,	0x0105,  8},
 2749:     
 2750:     {0,				0x0104, 14},
 2751:     {-1, 0, 0}
 2752: };
 2753: 
 2754: static char *
 2755: mlx_diagnose_command(struct mlx_command *mc)
 2756: {
 2757:     static char	unkmsg[80];
 2758:     int		i;
 2759:     
 2760:     /* look up message in table */
 2761:     for (i = 0; mlx_messages[i].command != -1; i++)
 2762: 	if (((mc->mc_mailbox[0] == mlx_messages[i].command) || (mlx_messages[i].command == 0)) &&
 2763: 	    (mc->mc_status == mlx_messages[i].status))
 2764: 	    return(mlx_status_messages[mlx_messages[i].msg]);
 2765: 	
 2766:     sprintf(unkmsg, "unknown response 0x%x for command 0x%x", (int)mc->mc_status, (int)mc->mc_mailbox[0]);
 2767:     return(unkmsg);
 2768: }
 2769: 
 2770: /*******************************************************************************
 2771:  * Print a string describing the controller (sc)
 2772:  */
 2773: static struct 
 2774: {
 2775:     int		hwid;
 2776:     char	*name;
 2777: } mlx_controller_names[] = {
 2778:     {0x01,	"960P/PD"},
 2779:     {0x02,	"960PL"},
 2780:     {0x10,	"960PG"},
 2781:     {0x11,	"960PJ"},
 2782:     {0x12,	"960PR"},
 2783:     {0x13,	"960PT"},
 2784:     {0x14,	"960PTL0"},
 2785:     {0x15,	"960PRL"},
 2786:     {0x16,	"960PTL1"},
 2787:     {0x20,	"1164PVX"},
 2788:     {-1, NULL}
 2789: };
 2790: 
 2791: static void
 2792: mlx_describe_controller(struct mlx_softc *sc) 
 2793: {
 2794:     static char		buf[80];
 2795:     char		*model;
 2796:     int			i;
 2797: 
 2798:     for (i = 0, model = NULL; mlx_controller_names[i].name != NULL; i++) {
 2799: 	if ((sc->mlx_enq2->me_hardware_id & 0xff) == mlx_controller_names[i].hwid) {
 2800: 	    model = mlx_controller_names[i].name;
 2801: 	    break;
 2802: 	}
 2803:     }
 2804:     if (model == NULL) {
 2805: 	sprintf(buf, " model 0x%x", sc->mlx_enq2->me_hardware_id & 0xff);
 2806: 	model = buf;
 2807:     }
 2808:     device_printf(sc->mlx_dev, "DAC%s, %d channel%s, firmware %d.%02d-%c-%02d, %dMB RAM\n",
 2809: 		  model, 
 2810: 		  sc->mlx_enq2->me_actual_channels, 
 2811: 		  sc->mlx_enq2->me_actual_channels > 1 ? "s" : "",
 2812: 		  sc->mlx_enq2->me_firmware_id & 0xff,
 2813: 		  (sc->mlx_enq2->me_firmware_id >> 8) & 0xff,
 2814: 		  (sc->mlx_enq2->me_firmware_id >> 24) & 0xff,
 2815: 		  (sc->mlx_enq2->me_firmware_id >> 16) & 0xff,
 2816: 		  sc->mlx_enq2->me_mem_size / (1024 * 1024));
 2817: 
 2818:     if (bootverbose) {
 2819: 	device_printf(sc->mlx_dev, "  Hardware ID                 0x%08x\n", sc->mlx_enq2->me_hardware_id);
 2820: 	device_printf(sc->mlx_dev, "  Firmware ID                 0x%08x\n", sc->mlx_enq2->me_firmware_id);
 2821: 	device_printf(sc->mlx_dev, "  Configured/Actual channels  %d/%d\n", sc->mlx_enq2->me_configured_channels,
 2822: 		      sc->mlx_enq2->me_actual_channels);
 2823: 	device_printf(sc->mlx_dev, "  Max Targets                 %d\n", sc->mlx_enq2->me_max_targets);
 2824: 	device_printf(sc->mlx_dev, "  Max Tags                    %d\n", sc->mlx_enq2->me_max_tags);
 2825: 	device_printf(sc->mlx_dev, "  Max System Drives           %d\n", sc->mlx_enq2->me_max_sys_drives);
 2826: 	device_printf(sc->mlx_dev, "  Max Arms                    %d\n", sc->mlx_enq2->me_max_arms);
 2827: 	device_printf(sc->mlx_dev, "  Max Spans                   %d\n", sc->mlx_enq2->me_max_spans);
 2828: 	device_printf(sc->mlx_dev, "  DRAM/cache/flash/NVRAM size %d/%d/%d/%d\n", sc->mlx_enq2->me_mem_size,
 2829: 		      sc->mlx_enq2->me_cache_size, sc->mlx_enq2->me_flash_size, sc->mlx_enq2->me_nvram_size);
 2830: 	device_printf(sc->mlx_dev, "  DRAM type                   %d\n", sc->mlx_enq2->me_mem_type);
 2831: 	device_printf(sc->mlx_dev, "  Clock Speed                 %dns\n", sc->mlx_enq2->me_clock_speed);
 2832: 	device_printf(sc->mlx_dev, "  Hardware Speed              %dns\n", sc->mlx_enq2->me_hardware_speed);
 2833: 	device_printf(sc->mlx_dev, "  Max Commands                %d\n", sc->mlx_enq2->me_max_commands);
 2834: 	device_printf(sc->mlx_dev, "  Max SG Entries              %d\n", sc->mlx_enq2->me_max_sg);
 2835: 	device_printf(sc->mlx_dev, "  Max DP                      %d\n", sc->mlx_enq2->me_max_dp);
 2836: 	device_printf(sc->mlx_dev, "  Max IOD                     %d\n", sc->mlx_enq2->me_max_iod);
 2837: 	device_printf(sc->mlx_dev, "  Max Comb                    %d\n", sc->mlx_enq2->me_max_comb);
 2838: 	device_printf(sc->mlx_dev, "  Latency                     %ds\n", sc->mlx_enq2->me_latency);
 2839: 	device_printf(sc->mlx_dev, "  SCSI Timeout                %ds\n", sc->mlx_enq2->me_scsi_timeout);
 2840: 	device_printf(sc->mlx_dev, "  Min Free Lines              %d\n", sc->mlx_enq2->me_min_freelines);
 2841: 	device_printf(sc->mlx_dev, "  Rate Constant               %d\n", sc->mlx_enq2->me_rate_const);
 2842: 	device_printf(sc->mlx_dev, "  MAXBLK                      %d\n", sc->mlx_enq2->me_maxblk);
 2843: 	device_printf(sc->mlx_dev, "  Blocking Factor             %d sectors\n", sc->mlx_enq2->me_blocking_factor);
 2844: 	device_printf(sc->mlx_dev, "  Cache Line Size             %d blocks\n", sc->mlx_enq2->me_cacheline);
 2845: 	device_printf(sc->mlx_dev, "  SCSI Capability             %s%dMHz, %d bit\n", 
 2846: 		      sc->mlx_enq2->me_scsi_cap & (1<<4) ? "differential " : "",
 2847: 		      (1 << ((sc->mlx_enq2->me_scsi_cap >> 2) & 3)) * 10,
 2848: 		      8 << (sc->mlx_enq2->me_scsi_cap & 0x3));
 2849: 	device_printf(sc->mlx_dev, "  Firmware Build Number       %d\n", sc->mlx_enq2->me_firmware_build);
 2850: 	device_printf(sc->mlx_dev, "  Fault Management Type       %d\n", sc->mlx_enq2->me_fault_mgmt_type);
 2851: 	device_printf(sc->mlx_dev, "  Features                    %b\n", sc->mlx_enq2->me_firmware_features,
 2852: 		      "\20\4Background Init\3Read Ahead\2MORE\1Cluster\n");
 2853: 	
 2854:     }
 2855: }
 2856: 
 2857: /*******************************************************************************
 2858:  * Emit a string describing the firmware handshake status code, and return a flag 
 2859:  * indicating whether the code represents a fatal error.
 2860:  *
 2861:  * Error code interpretations are from the Linux driver, and don't directly match
 2862:  * the messages printed by Mylex's BIOS.  This may change if documentation on the
 2863:  * codes is forthcoming.
 2864:  */
 2865: static int
 2866: mlx_fw_message(struct mlx_softc *sc, int error, int param1, int param2)
 2867: {
 2868:     switch(error) {
 2869:     case 0x00:
 2870: 	device_printf(sc->mlx_dev, "physical drive %d:%d not responding\n", param2, param1);
 2871: 	break;
 2872:     case 0x08:
 2873: 	/* we could be neater about this and give some indication when we receive more of them */
 2874: 	if (!(sc->mlx_flags & MLX_SPINUP_REPORTED)) {
 2875: 	    device_printf(sc->mlx_dev, "spinning up drives...\n");
 2876: 	    sc->mlx_flags |= MLX_SPINUP_REPORTED;
 2877: 	}
 2878: 	break;
 2879:     case 0x30:
 2880: 	device_printf(sc->mlx_dev, "configuration checksum error\n");
 2881: 	break;
 2882:     case 0x60:
 2883: 	device_printf(sc->mlx_dev, "mirror race recovery failed\n");
 2884: 	break;
 2885:     case 0x70:
 2886: 	device_printf(sc->mlx_dev, "mirror race recovery in progress\n");
 2887: 	break;
 2888:     case 0x90:
 2889: 	device_printf(sc->mlx_dev, "physical drive %d:%d COD mismatch\n", param2, param1);
 2890: 	break;
 2891:     case 0xa0:
 2892: 	device_printf(sc->mlx_dev, "logical drive installation aborted\n");
 2893: 	break;
 2894:     case 0xb0:
 2895: 	device_printf(sc->mlx_dev, "mirror race on a critical system drive\n");
 2896: 	break;
 2897:     case 0xd0:
 2898: 	device_printf(sc->mlx_dev, "new controller configuration found\n");
 2899: 	break;
 2900:     case 0xf0:
 2901: 	device_printf(sc->mlx_dev, "FATAL MEMORY PARITY ERROR\n");
 2902: 	return(1);
 2903:     default:
 2904: 	device_printf(sc->mlx_dev, "unknown firmware initialisation error %02x:%02x:%02x\n", error, param1, param2);
 2905: 	break;
 2906:     }
 2907:     return(0);
 2908: }
 2909: 
 2910: /********************************************************************************
 2911:  ********************************************************************************
 2912:                                                                 Utility Functions
 2913:  ********************************************************************************
 2914:  ********************************************************************************/
 2915: 
 2916: /********************************************************************************
 2917:  * Find the disk whose unit number is (unit) on this controller
 2918:  */
 2919: static struct mlx_sysdrive *
 2920: mlx_findunit(struct mlx_softc *sc, int unit)
 2921: {
 2922:     int		i;
 2923:     
 2924:     /* search system drives */
 2925:     for (i = 0; i < MLX_MAXDRIVES; i++) {
 2926: 	/* is this one attached? */
 2927: 	if (sc->mlx_sysdrive[i].ms_disk != 0) {
 2928: 	    /* is this the one? */
 2929: 	    if (unit == device_get_unit(sc->mlx_sysdrive[i].ms_disk))
 2930: 		return(&sc->mlx_sysdrive[i]);
 2931: 	}
 2932:     }
 2933:     return(NULL);
 2934: }