The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/raid/mlx/mlx.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 3ab475d2c092dad6b4280b8967ec3f30


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.